The current way we handle with auth token is manual and very error prone. The semanthics are also confusing and do not make clear how tokens are stored such that manipulating them is difficult. For example it was unclar in the code whether password tokens where 0 terminated and whether the length would incliude the null termination byte or not.
This code creates a standard structure called sss_auth_token that has a full set of getters and setters.
Simo.
Note: I wanted to make this structure completely opaque but it would have required a lot more allocations and pointers, and made the patchset larger.
Fixes: https://fedorahosted.org/sssd/ticket/1586
Simo Sorce (4): Code can only check for cached passwords Add function to safely wipe memory. Add authtok utility functions. Change pam data auth tokens.
Makefile.am | 4 + src/db/sysdb.h | 3 +- src/db/sysdb_ops.c | 13 +- src/providers/data_provider.h | 9 +- src/providers/dp_auth_util.c | 77 ++++++---- src/providers/dp_pam_data_util.c | 113 ++++++++------- src/providers/ipa/ipa_auth.c | 6 +- src/providers/krb5/krb5_auth.c | 45 +++--- src/providers/krb5/krb5_child.c | 148 ++++++++++--------- src/providers/krb5/krb5_child_handler.c | 59 ++++++-- .../krb5/krb5_delayed_online_authentication.c | 50 ++++--- src/providers/krb5/krb5_renew_tgt.c | 18 +-- src/providers/ldap/ldap_auth.c | 90 +++++------- src/providers/ldap/sdap_async.c | 4 +- src/providers/ldap/sdap_async.h | 7 +- src/providers/ldap/sdap_async_connection.c | 85 ++++++----- src/providers/proxy/proxy.h | 7 +- src/providers/proxy/proxy_auth.c | 14 +- src/providers/proxy/proxy_child.c | 51 ++++--- src/responder/pam/pam_LOCAL_domain.c | 52 +++---- src/responder/pam/pamsrv_cmd.c | 159 ++++++++++++--------- src/tests/krb5_child-test.c | 13 +- src/tests/sysdb-tests.c | 6 +- src/util/authtok.c | 146 +++++++++++++++++++ src/util/authtok.h | 137 ++++++++++++++++++ src/util/util.c | 9 ++ src/util/util.h | 10 ++ 27 files changed, 856 insertions(+), 479 deletions(-) create mode 100644 src/util/authtok.c create mode 100644 src/util/authtok.h
Make it clear to the API users that we can not take arbitrary auth tokens. We can only take a password for now so simplify and clarify the interface.
Signed-off-by: Simo Sorce simo@redhat.com --- src/db/sysdb.h | 3 +-- src/db/sysdb_ops.c | 12 +----------- src/providers/krb5/krb5_auth.c | 21 +++++++++++++++++---- src/responder/pam/pamsrv_cmd.c | 39 ++++++++++++++++++++++++--------------- src/tests/sysdb-tests.c | 6 ++---- 5 files changed, 45 insertions(+), 36 deletions(-)
diff --git a/src/db/sysdb.h b/src/db/sysdb.h index 0ce6beaa361bcb5930e64c31fc3763a230881e9a..9fda885211024e666bf592e05e4c8701ff409998 100644 --- a/src/db/sysdb.h +++ b/src/db/sysdb.h @@ -749,8 +749,7 @@ errno_t check_failed_login_attempts(struct confdb_ctx *cdb, time_t *delayed_until); int sysdb_cache_auth(struct sysdb_ctx *sysdb, const char *name, - const uint8_t *authtok, - size_t authtok_size, + const char *password, struct confdb_ctx *cdb, bool just_check, time_t *_expire_date, diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c index 52f0cef54b9819b1f5d754dcbd56abd1d7cb0e96..9f476e98ef0c09f39659d52b927224a20e42db07 100644 --- a/src/db/sysdb_ops.c +++ b/src/db/sysdb_ops.c @@ -2654,8 +2654,7 @@ done:
int sysdb_cache_auth(struct sysdb_ctx *sysdb, const char *name, - const uint8_t *authtok, - size_t authtok_size, + const char *password, struct confdb_ctx *cdb, bool just_check, time_t *_expire_date, @@ -2670,7 +2669,6 @@ int sysdb_cache_auth(struct sysdb_ctx *sysdb, struct ldb_message *ldb_msg; const char *userhash; char *comphash; - char *password = NULL; uint64_t lastLogin = 0; int cred_expiration; uint32_t failed_login_attempts = 0; @@ -2756,13 +2754,6 @@ int sysdb_cache_auth(struct sysdb_ctx *sysdb,
/* TODO: verify user account (disabled, expired ...) */
- password = talloc_strndup(tmp_ctx, (const char *)authtok, authtok_size); - if (password == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - ret = ENOMEM; - goto done; - } - userhash = ldb_msg_find_attr_as_string(ldb_msg, SYSDB_CACHEDPWD, NULL); if (userhash == NULL || *userhash == '\0') { DEBUG(4, ("Cached credentials not available.\n")); @@ -2846,7 +2837,6 @@ done: if (_delayed_until != NULL) { *_delayed_until = delayed_until; } - if (password) for (i = 0; password[i]; i++) password[i] = 0; if (ret) { ldb_transaction_cancel(sysdb->ldb); } else { diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c index 70dd988a7d28d19fe09946eedd90d713b35a4621..715f8601a77a8a3291f7b6c35b6a59b8a9b85c9b 100644 --- a/src/providers/krb5/krb5_auth.c +++ b/src/providers/krb5/krb5_auth.c @@ -277,16 +277,23 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, struct pam_data *pd, uid_t uid, int *pam_status, int *dp_err) { + char *password = NULL; errno_t ret;
- ret = sysdb_cache_auth(sysdb, pd->user, pd->authtok, - pd->authtok_size, cdb, true, NULL, - NULL); + password = talloc_strndup(state, pd->authtok, pd->authtok_size); + if (!password) { + DEBUG(0, ("Out of memory copying password\n")); + *pam_status = PAM_SYSTEM_ERR; + *dp_err = DP_ERR_OK; + return; + } + + ret = sysdb_cache_auth(sysdb, pd->user, password, cdb, true, NULL, NULL); if (ret != EOK) { DEBUG(1, ("Offline authentication failed\n")); *pam_status = PAM_SYSTEM_ERR; *dp_err = DP_ERR_OK; - return; + goto done; }
ret = add_user_to_delayed_online_authentication(krb5_ctx, pd, uid); @@ -296,6 +303,12 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, } *pam_status = PAM_AUTHINFO_UNAVAIL; *dp_err = DP_ERR_OFFLINE; + +done: + if (password) { + for (i = 0; password[i]; i++) password[i] = 0; + talloc_zfree(password); + } }
static errno_t krb5_auth_prepare_ccache_file(struct krb5child_req *kr, diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index 2b20544d1baf78ade232f93a2c91378ec6a7645c..8ab90e30e3f553c95a43db3ce69799b8b6d24d76 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -731,7 +731,6 @@ static void pam_reply(struct pam_auth_req *preq) struct timeval tv; struct tevent_timer *te; struct pam_data *pd; - struct sysdb_ctx *sysdb; struct pam_ctx *pctx; uint32_t user_info_type; time_t exp_date = -1; @@ -751,24 +750,34 @@ static void pam_reply(struct pam_auth_req *preq) if ((preq->domain != NULL) && (preq->domain->cache_credentials == true) && (pd->offline_auth == false)) { + const char *password = NULL;
- /* do auth with offline credentials */ - pd->offline_auth = true; + /* do auth with offline credentials */ + pd->offline_auth = true;
- sysdb = preq->domain->sysdb; - if (sysdb == NULL) { - DEBUG(0, ("Fatal: Sysdb CTX not found for " - "domain [%s]!\n", preq->domain->name)); - goto done; - } + if (preq->domain->sysdb == NULL) { + DEBUG(0, ("Fatal: Sysdb CTX not found for domain" + " [%s]!\n", preq->domain->name)); + goto done; + }
- ret = sysdb_cache_auth(sysdb, pd->user, - pd->authtok, pd->authtok_size, - pctx->rctx->cdb, false, - &exp_date, &delay_until); + password = talloc_strndup(preq, pd->authtok, pd->authtok_size); + if (!password) { + DEBUG(0, ("Fatal: Out of memory copying password\n")); + goto done; + }
- pam_cache_auth_done(preq, ret, exp_date, delay_until); - return; + ret = sysdb_cache_auth(preq->domain->sysdb, + pd->user, password, + pctx->rctx->cdb, false, + &exp_date, &delay_until); + + pam_cache_auth_done(preq, ret, exp_date, delay_until); + if (password) { + for (i = 0; password[i]; i++) password[i] = 0; + talloc_zfree(password); + } + return; } break; case SSS_PAM_CHAUTHTOK_PRELIM: diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c index d9afe7b8830c05dec8bae534f154270bedda84e8..7c111c74f7b06e30475619e9e0f455a7b86f4f2f 100644 --- a/src/tests/sysdb-tests.c +++ b/src/tests/sysdb-tests.c @@ -1492,8 +1492,7 @@ static void cached_authentication_without_expiration(const char *username, return; }
- ret = sysdb_cache_auth(test_ctx->sysdb, data->username, - (const uint8_t *)password, strlen(password), + ret = sysdb_cache_auth(test_ctx->sysdb, data->username, password, test_ctx->confdb, false, &expire_date, &delayed_until);
fail_unless(ret == expected_result, "sysdb_cache_auth request does not " @@ -1552,8 +1551,7 @@ static void cached_authentication_with_expiration(const char *username, data->attrs, SYSDB_MOD_REP); fail_unless(ret == EOK, "Could not modify user %s", data->username);
- ret = sysdb_cache_auth(test_ctx->sysdb, data->username, - (const uint8_t *) password, strlen(password), + ret = sysdb_cache_auth(test_ctx->sysdb, data->username, password, test_ctx->confdb, false, &expire_date, &delayed_until);
fail_unless(ret == expected_result,
This is useful for wiping passwords, as it prevents the compiler from optimizing out a memset to zero before a free()
Signed-off-by: Simo Sorce simo@redhat.com --- src/util/util.c | 9 +++++++++ src/util/util.h | 10 ++++++++++ 2 files changed, 19 insertions(+)
diff --git a/src/util/util.c b/src/util/util.c index b812ef1b118803129caae25247efcbc1194b22f5..061291c04bb581082aa98d79b6b1ec1a1d1090ac 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -634,3 +634,12 @@ remove_ipv6_brackets(char *ipv6addr)
return EOK; } + +void safezero(void *data, size_t size) +{ + volatile uint8_t *p = data; + + while (size--) { + *p++ = 0; + } +} diff --git a/src/util/util.h b/src/util/util.h index a96f519ad959b8706f31c5cf7e4204c77e39b737..db501c912a151613f8dc4c31f1899fd3a3568b02 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -528,6 +528,16 @@ sss_escape_ip_address(TALLOC_CTX *mem_ctx, int family, const char *addr); errno_t remove_ipv6_brackets(char *ipv6addr);
+ +/** + * @brief Safely zero a segment of memory, + * prevents the compiler from optimizing out + * + * @param data The address of buffer to wipe + * @param s Size of the buffer + */ +void safezero(void *data, size_t size); + /* from sss_tc_utf8.c */ char * sss_tc_utf8_str_tolower(TALLOC_CTX *mem_ctx, const char *s);
These functions allow handling of auth tokens in a completely opaque way, with clear semantics and accessor fucntions that guarantee consistency, proper access to data and error conditions.
Signed-off-by: Simo Sorce simo@redhat.com --- Makefile.am | 2 + src/util/authtok.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/util/authtok.h | 137 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 285 insertions(+) create mode 100644 src/util/authtok.c create mode 100644 src/util/authtok.h
diff --git a/Makefile.am b/Makefile.am index ee7e198f1d609ce2d9a81f7e9562ee2e5c93966b..0404a854ddd104bf173ad2f4909c6728f3a3af95 100644 --- a/Makefile.am +++ b/Makefile.am @@ -368,6 +368,7 @@ dist_noinst_HEADERS = \ src/util/murmurhash3.h \ src/util/mmap_cache.h \ src/util/atomic_io.h \ + src/util/authtok.h \ src/monitor/monitor.h \ src/monitor/monitor_interfaces.h \ src/responder/common/responder.h \ @@ -506,6 +507,7 @@ libsss_util_la_SOURCES = \ src/util/sss_tc_utf8.c \ src/util/murmurhash3.c \ src/util/atomic_io.c \ + src/util/authtok.c \ src/util/sss_selinux.c \ src/util/domain_info_utils.c libsss_util_la_LIBADD = \ diff --git a/src/util/authtok.c b/src/util/authtok.c new file mode 100644 index 0000000000000000000000000000000000000000..91cc43fe51ee94827e56b25d0d26a214edc266db --- /dev/null +++ b/src/util/authtok.c @@ -0,0 +1,146 @@ +/* + SSSD - auth utils + + Copyright (C) Simo Sorce simo@redhat.com 2012 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses/. +*/ + +#include "authtok.h" + +enum sss_authtok_type sss_authtok_get_type(struct sss_auth_token *tok) +{ + return tok->type; +} + +size_t sss_authtok_get_size(struct sss_auth_token *tok) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_PASSWORD: + case SSS_AUTHTOK_TYPE_CCFILE: + return tok->length + 1; + default: + return 0; + } +} + +errno_t sss_authtok_get_password(struct sss_auth_token *tok, + const char **pwd, size_t *len) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_EMPTY: + return ENOENT; + case SSS_AUTHTOK_TYPE_PASSWORD: + *pwd = (const char *)tok->data; + if (len) { + *len = tok->length; + } + return EOK; + default: + return EACCES; + } +} + +errno_t sss_authtok_set_password(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *password, size_t len) +{ + sss_authtok_set_empty(tok); + + if (len == 0) { + len = strlen(password); + } + + if (len != 0) { + tok->data = talloc_named(mem_ctx, len + 1, "password"); + if (!tok->data) { + return ENOMEM; + } + memcpy(tok->data, password, len); + tok->data[len] = '\0'; + tok->type = SSS_AUTHTOK_TYPE_PASSWORD; + tok->length = len; + } + + return EOK; +} + +errno_t sss_authtok_get_ccfile(struct sss_auth_token *tok, + const char **ccfile, size_t *len) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_EMPTY: + return ENOENT; + case SSS_AUTHTOK_TYPE_CCFILE: + *ccfile = (const char *)tok->data; + if (len) { + *len = tok->length; + } + return EOK; + default: + return EACCES; + } +} + +errno_t sss_authtok_set_ccfile(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *ccfile) +{ + sss_authtok_set_empty(tok); + + tok->data = (uint8_t *)talloc_strdup(mem_ctx, ccfile); + if (!tok->data) { + return ENOMEM; + } + tok->type = SSS_AUTHTOK_TYPE_CCFILE; + tok->length = strlen(ccfile); + + return EOK; +} + +void sss_authtok_set_empty(struct sss_auth_token *tok) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_EMPTY: + return; + case SSS_AUTHTOK_TYPE_PASSWORD: + safezero(tok->data, tok->length); + default: + break; + } + + tok->type = SSS_AUTHTOK_TYPE_EMPTY; + talloc_zfree(tok->data); + tok->length = 0; +} + +errno_t sss_authtok_copy(TALLOC_CTX *mem_ctx, + struct sss_auth_token *src, + struct sss_auth_token *dst) +{ + sss_authtok_set_empty(dst); + + if (src->type == SSS_AUTHTOK_TYPE_EMPTY) { + return EOK; + } + + dst->data = talloc_memdup(mem_ctx, src->data, src->length); + if (!dst->data) { + return ENOMEM; + } + dst->length = src->length; + dst->type = src->type; + + return EOK; +} diff --git a/src/util/authtok.h b/src/util/authtok.h new file mode 100644 index 0000000000000000000000000000000000000000..2adb0b9e02597bb8c760c26fd715b6414fa81bf5 --- /dev/null +++ b/src/util/authtok.h @@ -0,0 +1,137 @@ +/* + SSSD - auth utils + + Copyright (C) Simo Sorce simo@redhat.com 2012 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses/. +*/ + +#ifndef __AUTHTOK_H__ +#define __AUTHTOK_H__ + +#include "util/util.h" +#include "sss_client/sss_cli.h" + +/* Auth token structure, + * please never use directly. + * Use ss_authtok_* accesor functions instead + */ +struct sss_auth_token { + enum sss_authtok_type type; + uint8_t *data; + size_t length; +}; + +/** + * @brief Returns the token type + * + * @param tok A pointer to an sss_auth_token + * + * @return A sss_authtok_type (empty, password, ...) + */ +enum sss_authtok_type sss_authtok_get_type(struct sss_auth_token *tok); + +/** + * @brief Returns the token size + * + * @param tok A pointer to an sss_auth_token + * + * @return The current size of the token payload + */ +size_t sss_authtok_get_size(struct sss_auth_token *tok); + +/** + * @brief Returns a const string if the auth token is of type + SSS_AUTHTOK_TYPE_PASSWORD, otherwise it returns an error + * + * @param tok A pointer to an sss_auth_token + * @param pwd A pointer to a const char *, that will point to a null + * terminated string + * @param len The length of the password string + * + * @return EOK on success + * ENOENT if the token is empty + * EACCESS if the token is not a password token + */ +errno_t sss_authtok_get_password(struct sss_auth_token *tok, + const char **pwd, size_t *len); + +/** + * @brief Set a password into a an auth token, replacing any previous data + * + * @param mem_ctx A memory context use to allocate the internal data + * @param tok A pointer to a sss_auth_token structure to change + * @param password A string + * @param len The length of the string or, if 0 is passed, + * then strlen(password) will be used internally. + * + * @return EOK on success + * ENOMEM on error + */ +errno_t sss_authtok_set_password(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *password, size_t len); + +/** + * @brief Returns a const string if the auth token is of type + SSS_AUTHTOK_TYPE_CCFILE, otherwise it returns an error + * + * @param tok A pointer to an sss_auth_token + * @param ccfile A pointer to a const char *, that will point to a null + * terminated string + * @param len The length of the string + * + * @return EOK on success + * ENOENT if the token is empty + * EACCESS if the token is not a password token + */ +errno_t sss_authtok_get_ccfile(struct sss_auth_token *tok, + const char **ccfile, size_t *len); + +/** + * @brief Set a cc file name into a an auth token, replacing any previous data + * + * @param mem_ctx A memory context use to allocate the internal data + * @param tok A pointer to a sss_auth_token structure to change + * @param ccfile A null terminated string + * + * @return EOK on success + * ENOMEM on error + */ +errno_t sss_authtok_set_ccfile(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *ccfile); + +/** + * @brief Resets an auth token to the empty status + * + * @param tok A pointer to a sss_auth_token structure to reset + */ +void sss_authtok_set_empty(struct sss_auth_token *tok); + +/** + * @brief Copy an auth token from source to destination + * + * @param mem_ctx The memory context to use for allocations on dst + * @param src The source auth token + * @param dst The destination auth token + * + * @return EOK on success + * ENOMEM on error + */ +errno_t sss_authtok_copy(TALLOC_CTX *mem_ctx, + struct sss_auth_token *src, + struct sss_auth_token *dst); + +#endif /* __AUTHTOK_H__ */
Use the new authtok abstraction and interfaces throught the code.
Signed-off-by: Simo Sorce simo@redhat.com --- Makefile.am | 2 + src/db/sysdb_ops.c | 1 - src/providers/data_provider.h | 9 +- src/providers/dp_auth_util.c | 77 ++++++----- src/providers/dp_pam_data_util.c | 113 ++++++++-------- src/providers/ipa/ipa_auth.c | 6 +- src/providers/krb5/krb5_auth.c | 48 ++++--- src/providers/krb5/krb5_child.c | 148 +++++++++++---------- src/providers/krb5/krb5_child_handler.c | 59 ++++++-- .../krb5/krb5_delayed_online_authentication.c | 50 ++++--- src/providers/krb5/krb5_renew_tgt.c | 18 +-- src/providers/ldap/ldap_auth.c | 90 +++++-------- src/providers/ldap/sdap_async.c | 4 +- src/providers/ldap/sdap_async.h | 7 +- src/providers/ldap/sdap_async_connection.c | 85 ++++++------ src/providers/proxy/proxy.h | 7 +- src/providers/proxy/proxy_auth.c | 14 +- src/providers/proxy/proxy_child.c | 51 ++++--- src/responder/pam/pam_LOCAL_domain.c | 52 +++----- src/responder/pam/pamsrv_cmd.c | 134 ++++++++++--------- src/tests/krb5_child-test.c | 13 +- 21 files changed, 526 insertions(+), 462 deletions(-)
diff --git a/Makefile.am b/Makefile.am index 0404a854ddd104bf173ad2f4909c6728f3a3af95..8c4e33b0404f8ee319726e004309e788e62571d6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1444,6 +1444,7 @@ krb5_child_SOURCES = \ src/util/user_info_msg.c \ src/util/sss_krb5.c \ src/util/atomic_io.c \ + src/util/authtok.c \ src/util/util.c \ src/util/signal.c krb5_child_CFLAGS = \ @@ -1463,6 +1464,7 @@ ldap_child_SOURCES = \ src/providers/ldap/ldap_child.c \ src/util/sss_krb5.c \ src/util/atomic_io.c \ + src/util/authtok.c \ src/util/util.c \ src/util/signal.c ldap_child_CFLAGS = \ diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c index 9f476e98ef0c09f39659d52b927224a20e42db07..8349115ce9e34a894b8f115807bc666a25447b8c 100644 --- a/src/db/sysdb_ops.c +++ b/src/db/sysdb_ops.c @@ -2677,7 +2677,6 @@ int sysdb_cache_auth(struct sysdb_ctx *sysdb, time_t expire_date = -1; time_t delayed_until = -1; int ret; - int i;
if (name == NULL || *name == '\0') { DEBUG(1, ("Missing user name.\n")); diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h index 2d4d1ddbff16cd0848382c6d7e1113215aca4999..a48ee45afd117483fd182307f4f0705331bbd229 100644 --- a/src/providers/data_provider.h +++ b/src/providers/data_provider.h @@ -41,6 +41,7 @@ #include "sbus/sssd_dbus.h" #include "sbus/sbus_client.h" #include "sss_client/sss_cli.h" +#include "util/authtok.h"
#define DATA_PROVIDER_VERSION 0x0001 #define DATA_PROVIDER_PIPE "private/sbus-dp" @@ -162,18 +163,14 @@ struct response_data {
struct pam_data { int cmd; - uint32_t authtok_type; - uint32_t authtok_size; - uint32_t newauthtok_type; - uint32_t newauthtok_size; char *domain; char *user; char *service; char *tty; char *ruser; char *rhost; - uint8_t *authtok; - uint8_t *newauthtok; + struct sss_auth_token authtok; + struct sss_auth_token newauthtok; uint32_t cli_pid;
int pam_status; diff --git a/src/providers/dp_auth_util.c b/src/providers/dp_auth_util.c index 9a67564b78e558642f4116528d210251a0d9b5fd..788e31627157083b16327e859e7c51372fa79e0a 100644 --- a/src/providers/dp_auth_util.c +++ b/src/providers/dp_auth_util.c @@ -24,30 +24,43 @@ bool dp_pack_pam_request(DBusMessage *msg, struct pam_data *pd) { dbus_bool_t db_ret; + const char *service; + const char *tty; + const char *ruser; + const char *rhost; + uint32_t authtok_type; + uint32_t authtok_length; + uint8_t *authtok_data; + uint32_t new_authtok_type; + uint32_t new_authtok_length; + uint8_t *new_authtok_data;
if (pd->user == NULL) return false; - if (pd->service == NULL) pd->service = talloc_strdup(pd, ""); - if (pd->tty == NULL) pd->tty = talloc_strdup(pd, ""); - if (pd->ruser == NULL) pd->ruser = talloc_strdup(pd, ""); - if (pd->rhost == NULL) pd->rhost = talloc_strdup(pd, ""); - + service = pd->service ? pd->service : ""; + tty = pd->tty ? pd->tty : ""; + ruser = pd->ruser ? pd->ruser : ""; + rhost = pd->rhost ? pd->rhost : ""; + authtok_type = pd->authtok.type; + authtok_data = pd->authtok.data; + authtok_length = pd->authtok.length; + new_authtok_type = pd->newauthtok.type; + new_authtok_data = pd->newauthtok.data; + new_authtok_length = pd->newauthtok.length;
db_ret = dbus_message_append_args(msg, DBUS_TYPE_INT32, &(pd->cmd), DBUS_TYPE_STRING, &(pd->user), DBUS_TYPE_STRING, &(pd->domain), - DBUS_TYPE_STRING, &(pd->service), - DBUS_TYPE_STRING, &(pd->tty), - DBUS_TYPE_STRING, &(pd->ruser), - DBUS_TYPE_STRING, &(pd->rhost), - DBUS_TYPE_UINT32, &(pd->authtok_type), + DBUS_TYPE_STRING, &service, + DBUS_TYPE_STRING, &tty, + DBUS_TYPE_STRING, &ruser, + DBUS_TYPE_STRING, &rhost, + DBUS_TYPE_UINT32, &authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd->authtok), - (pd->authtok_size), - DBUS_TYPE_UINT32, &(pd->newauthtok_type), + &authtok_data, authtok_length, + DBUS_TYPE_UINT32, &new_authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd->newauthtok), - pd->newauthtok_size, + &new_authtok_data, new_authtok_length, DBUS_TYPE_INT32, &(pd->priv), DBUS_TYPE_UINT32, &(pd->cli_pid), DBUS_TYPE_INVALID); @@ -61,6 +74,12 @@ bool dp_unpack_pam_request(DBusMessage *msg, TALLOC_CTX *mem_ctx, dbus_bool_t db_ret; int ret; struct pam_data pd; + uint32_t authtok_type; + uint32_t authtok_length; + uint8_t *authtok_data; + uint32_t new_authtok_type; + uint32_t new_authtok_length; + uint8_t *new_authtok_data;
memset(&pd, 0, sizeof(pd));
@@ -72,14 +91,12 @@ bool dp_unpack_pam_request(DBusMessage *msg, TALLOC_CTX *mem_ctx, DBUS_TYPE_STRING, &(pd.tty), DBUS_TYPE_STRING, &(pd.ruser), DBUS_TYPE_STRING, &(pd.rhost), - DBUS_TYPE_UINT32, &(pd.authtok_type), + DBUS_TYPE_UINT32, &authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd.authtok), - &(pd.authtok_size), - DBUS_TYPE_UINT32, &(pd.newauthtok_type), + &authtok_data, &authtok_length, + DBUS_TYPE_UINT32, &new_authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd.newauthtok), - &(pd.newauthtok_size), + &new_authtok_data, &new_authtok_length, DBUS_TYPE_INT32, &(pd.priv), DBUS_TYPE_UINT32, &(pd.cli_pid), DBUS_TYPE_INVALID); @@ -89,21 +106,21 @@ bool dp_unpack_pam_request(DBusMessage *msg, TALLOC_CTX *mem_ctx, return false; }
+ pd.authtok.type = authtok_type; + pd.authtok.data = authtok_data; + pd.authtok.length = authtok_length; + pd.newauthtok.type = new_authtok_type; + pd.newauthtok.data = new_authtok_data; + pd.newauthtok.length = new_authtok_length; + ret = copy_pam_data(mem_ctx, &pd, new_pd); if (ret != EOK) { DEBUG(1, ("copy_pam_data failed.\n")); return false; }
- if (pd.authtok_size != 0 && pd.authtok != NULL) { - memset(pd.authtok, 0, pd.authtok_size); - pd.authtok_size = 0; - } - - if (pd.newauthtok_size != 0 && pd.newauthtok != NULL) { - memset(pd.newauthtok, 0, pd.newauthtok_size); - pd.newauthtok_size = 0; - } + sss_authtok_set_empty(&pd.authtok); + sss_authtok_set_empty(&pd.newauthtok);
return true; } diff --git a/src/providers/dp_pam_data_util.c b/src/providers/dp_pam_data_util.c index 889c47f00bfb49effab982ed40454b5120b84bf6..6d87add9d90b8645ca9893ce5650305feacedb76 100644 --- a/src/providers/dp_pam_data_util.c +++ b/src/providers/dp_pam_data_util.c @@ -25,26 +25,6 @@ #include "providers/data_provider.h"
-#define PD_STR_COPY(el) do { \ - if (old_pd->el != NULL) { \ - pd->el = talloc_strdup(pd, old_pd->el); \ - if (pd->el == NULL) { \ - DEBUG(1, ("talloc_strdup failed.\n")); \ - goto failed; \ - } \ - } \ -} while(0) - -#define PD_MEM_COPY(el, size) do { \ - if (old_pd->el != NULL) { \ - pd->el = talloc_memdup(pd, old_pd->el, (size)); \ - if (pd->el == NULL) { \ - DEBUG(1, ("talloc_memdup failed.\n")); \ - goto failed; \ - } \ - } \ -} while(0) - #define PAM_SAFE_ITEM(item) item ? item : "not set"
static const char *pamcmd2str(int cmd) { @@ -72,17 +52,11 @@ int pam_data_destructor(void *ptr) { struct pam_data *pd = talloc_get_type(ptr, struct pam_data);
- if (pd->authtok_size != 0 && pd->authtok != NULL) { - memset(pd->authtok, 0, pd->authtok_size); - pd->authtok_size = 0; - } + /* make sure to wipe any password from memory before freeing */ + sss_authtok_set_empty(&pd->authtok); + sss_authtok_set_empty(&pd->newauthtok);
- if (pd->newauthtok_size != 0 && pd->newauthtok != NULL) { - memset(pd->newauthtok, 0, pd->newauthtok_size); - pd->newauthtok_size = 0; - } - - return EOK; + return 0; }
struct pam_data *create_pam_data(TALLOC_CTX *mem_ctx) @@ -100,41 +74,72 @@ struct pam_data *create_pam_data(TALLOC_CTX *mem_ctx) return pd; }
-errno_t copy_pam_data(TALLOC_CTX *mem_ctx, struct pam_data *old_pd, - struct pam_data **new_pd) +errno_t copy_pam_data(TALLOC_CTX *mem_ctx, struct pam_data *src, + struct pam_data **dst) { struct pam_data *pd = NULL; + errno_t ret;
pd = create_pam_data(mem_ctx); if (pd == NULL) { - DEBUG(1, ("create_pam_data failed.\n")); - return ENOMEM; + ret = ENOMEM; + goto failed; }
- pd->cmd = old_pd->cmd; - pd->authtok_type = old_pd->authtok_type; - pd->authtok_size = old_pd->authtok_size; - pd->newauthtok_type = old_pd->newauthtok_type; - pd->newauthtok_size = old_pd->newauthtok_size; - pd->priv = old_pd->priv; + pd->cmd = src->cmd; + pd->priv = src->priv;
- PD_STR_COPY(domain); - PD_STR_COPY(user); - PD_STR_COPY(service); - PD_STR_COPY(tty); - PD_STR_COPY(ruser); - PD_STR_COPY(rhost); - PD_MEM_COPY(authtok, old_pd->authtok_size); - PD_MEM_COPY(newauthtok, old_pd->newauthtok_size); - pd->cli_pid = old_pd->cli_pid; + pd->domain = talloc_strdup(pd, src->domain); + if (pd->domain == NULL && src->domain != NULL) { + ret = ENOMEM; + goto failed; + } + pd->user = talloc_strdup(pd, src->user); + if (pd->user == NULL && src->user != NULL) { + ret = ENOMEM; + goto failed; + } + pd->service = talloc_strdup(pd, src->service); + if (pd->service == NULL && src->service != NULL) { + ret = ENOMEM; + goto failed; + } + pd->tty = talloc_strdup(pd, src->tty); + if (pd->tty == NULL && src->tty != NULL) { + ret = ENOMEM; + goto failed; + } + pd->ruser = talloc_strdup(pd, src->ruser); + if (pd->ruser == NULL && src->ruser != NULL) { + ret = ENOMEM; + goto failed; + } + pd->rhost = talloc_strdup(pd, src->rhost); + if (pd->rhost == NULL && src->rhost != NULL) { + ret = ENOMEM; + goto failed; + } + + pd->cli_pid = src->cli_pid; + + ret = sss_authtok_copy(pd, &src->authtok, &pd->authtok); + if (ret) { + goto failed; + } + + ret = sss_authtok_copy(pd, &src->newauthtok, &pd->newauthtok); + if (ret) { + goto failed; + }
- *new_pd = pd; + *dst = pd;
return EOK;
failed: talloc_free(pd); - return ENOMEM; + DEBUG(1, ("copy_pam_data failed: (%d) %s.\n", ret, strerror(ret))); + return ret; }
void pam_print_data(int l, struct pam_data *pd) @@ -146,10 +151,8 @@ void pam_print_data(int l, struct pam_data *pd) DEBUG(l, ("tty: %s\n", PAM_SAFE_ITEM(pd->tty))); DEBUG(l, ("ruser: %s\n", PAM_SAFE_ITEM(pd->ruser))); DEBUG(l, ("rhost: %s\n", PAM_SAFE_ITEM(pd->rhost))); - DEBUG(l, ("authtok type: %d\n", pd->authtok_type)); - DEBUG(l, ("authtok size: %d\n", pd->authtok_size)); - DEBUG(l, ("newauthtok type: %d\n", pd->newauthtok_type)); - DEBUG(l, ("newauthtok size: %d\n", pd->newauthtok_size)); + DEBUG(l, ("authtok type: %d\n", sss_authtok_get_type(&pd->authtok))); + DEBUG(l, ("newauthtok type: %d\n", sss_authtok_get_type(&pd->newauthtok))); DEBUG(l, ("priv: %d\n", pd->priv)); DEBUG(l, ("cli_pid: %d\n", pd->cli_pid)); } diff --git a/src/providers/ipa/ipa_auth.c b/src/providers/ipa/ipa_auth.c index 2bd313b382448a8bd84f44b52e55b944c7b1d894..90760c0df574a04c14a81167e3071b60091da240 100644 --- a/src/providers/ipa/ipa_auth.c +++ b/src/providers/ipa/ipa_auth.c @@ -338,7 +338,6 @@ static void ipa_migration_flag_connect_done(struct tevent_req *req) const char **attrs; struct ldb_message *user_msg; const char *dn; - struct dp_opt_blob password; int dp_err = DP_ERR_FATAL; int ret;
@@ -380,11 +379,8 @@ static void ipa_migration_flag_connect_done(struct tevent_req *req) goto done; }
- password.data = state->pd->authtok; - password.length = state->pd->authtok_size; - req = sdap_auth_send(state, state->ev, state->sh, NULL, NULL, dn, - "password", password); + &state->pd->authtok); if (req == NULL) { DEBUG(SSSDBG_OP_FAILURE, ("sdap_auth_send failed.\n")); goto done; diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c index 715f8601a77a8a3291f7b6c35b6a59b8a9b85c9b..d33abe39e400ef03ef635cfd8fc839b35b0a460a 100644 --- a/src/providers/krb5/krb5_auth.c +++ b/src/providers/krb5/krb5_auth.c @@ -277,12 +277,12 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, struct pam_data *pd, uid_t uid, int *pam_status, int *dp_err) { - char *password = NULL; + const char *password = NULL; errno_t ret;
- password = talloc_strndup(state, pd->authtok, pd->authtok_size); - if (!password) { - DEBUG(0, ("Out of memory copying password\n")); + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + if (ret != EOK) { + DEBUG(0, ("Failed to get password [%d] %s\n", ret, strerror(ret))); *pam_status = PAM_SYSTEM_ERR; *dp_err = DP_ERR_OK; return; @@ -293,7 +293,7 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, DEBUG(1, ("Offline authentication failed\n")); *pam_status = PAM_SYSTEM_ERR; *dp_err = DP_ERR_OK; - goto done; + return; }
ret = add_user_to_delayed_online_authentication(krb5_ctx, pd, uid); @@ -303,12 +303,6 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, } *pam_status = PAM_AUTHINFO_UNAVAIL; *dp_err = DP_ERR_OFFLINE; - -done: - if (password) { - for (i = 0; password[i]; i++) password[i] = 0; - talloc_zfree(password); - } }
static errno_t krb5_auth_prepare_ccache_file(struct krb5child_req *kr, @@ -444,9 +438,17 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx, case SSS_PAM_AUTHENTICATE: case SSS_CMD_RENEW: case SSS_PAM_CHAUTHTOK: + if (sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { + DEBUG(1, ("Missing authtok for user [%s].\n", pd->user)); + state->pam_status = PAM_SYSTEM_ERR; + state->dp_err = DP_ERR_FATAL; + ret = EINVAL; + goto done; + } break; case SSS_PAM_CHAUTHTOK_PRELIM: - if (pd->priv == 1 && pd->authtok_size == 0) { + if (pd->priv == 1 && + sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { DEBUG(4, ("Password reset by root is not supported.\n")); state->pam_status = PAM_PERM_DENIED; state->dp_err = DP_ERR_OK; @@ -762,7 +764,7 @@ static void krb5_auth_done(struct tevent_req *subreq) struct krb5_child_response *res; const char *store_ccname; struct fo_server *search_srv; - char *password = NULL; + const char *password = NULL;
ret = handle_child_recv(subreq, pd, &buf, &len); talloc_zfree(subreq); @@ -1012,23 +1014,21 @@ static void krb5_auth_done(struct tevent_req *subreq) break; case SSS_PAM_AUTHENTICATE: case SSS_PAM_CHAUTHTOK_PRELIM: - password = talloc_size(state, pd->authtok_size + 1); - if (password != NULL) { - memcpy(password, pd->authtok, pd->authtok_size); - password[pd->authtok_size] = '\0'; - } + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); break; case SSS_PAM_CHAUTHTOK: - password = talloc_size(state, pd->newauthtok_size + 1); - if (password != NULL) { - memcpy(password, pd->newauthtok, pd->newauthtok_size); - password[pd->newauthtok_size] = '\0'; - } + ret = sss_authtok_get_password(&pd->newauthtok, + &password, NULL); break; default: DEBUG(0, ("unsupported PAM command [%d].\n", pd->cmd)); }
+ if (ret != EOK) { + DEBUG(0, ("Failed to get password [%d] %s\n", ret, strerror(ret))); + /* password caching failures are not fatal errors */ + } + if (password == NULL) { if (pd->cmd != SSS_CMD_RENEW) { DEBUG(0, ("password not available, offline auth may not work.\n")); @@ -1038,8 +1038,6 @@ static void krb5_auth_done(struct tevent_req *subreq) goto done; }
- talloc_set_destructor((TALLOC_CTX *)password, password_destructor); - ret = sysdb_cache_password(state->be_ctx->sysdb, pd->user, password); if (ret) { DEBUG(2, ("Failed to cache password, offline auth may not work." diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c index a92ba57bf3219cd6899a6b29e2f2555aae6bb323..6a00f07c365391d96e05fdb573842db3f3d7c89a 100644 --- a/src/providers/krb5/krb5_child.c +++ b/src/providers/krb5/krb5_child.c @@ -856,7 +856,7 @@ done: }
static krb5_error_code get_and_save_tgt(struct krb5_req *kr, - char *password) + const char *password) { krb5_error_code kerr = 0; int ret; @@ -877,7 +877,8 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr, DEBUG(SSSDBG_TRACE_FUNC, ("Attempting kinit for realm [%s]\n",realm_name)); kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - password, sss_krb5_prompter, kr, 0, + discard_const(password), + sss_krb5_prompter, kr, 0, NULL, kr->options); if (kerr != 0) { KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); @@ -972,8 +973,8 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) { int ret; krb5_error_code kerr = 0; - char *pass_str = NULL; - char *newpass_str = NULL; + const char *password = NULL; + const char *newpassword = NULL; int pam_status = PAM_SYSTEM_ERR; int result_code = -1; krb5_data result_code_string; @@ -988,20 +989,15 @@ static errno_t changepw_child(int fd, struct krb5_req *kr)
DEBUG(SSSDBG_TRACE_LIBS, ("Password change operation\n"));
- if (kr->pd->authtok_type != SSS_AUTHTOK_TYPE_PASSWORD) { + ret = sss_authtok_get_password(&kr->pd->authtok, &password, NULL); + if (ret != EOK) { + DEBUG(1, ("Failed to fetch current password [%d] %s.\n", + ret, strerror(ret))); pam_status = PAM_CRED_INSUFFICIENT; kerr = KRB5KRB_ERR_GENERIC; goto sendresponse; }
- pass_str = talloc_strndup(kr, (const char *) kr->pd->authtok, - kr->pd->authtok_size); - if (pass_str == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - kerr = KRB5KRB_ERR_GENERIC; - goto sendresponse; - } - changepw_princ = talloc_asprintf(kr, "%s@%s", SSSD_KRB5_CHANGEPW_PRINCIPAL, kr->krb5_ctx->realm); if (changepw_princ == NULL) { @@ -1022,7 +1018,8 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) DEBUG(SSSDBG_TRACE_FUNC, ("Attempting kinit for realm [%s]\n",realm_name)); kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - pass_str, prompter, kr, 0, + discard_const(password), + prompter, kr, 0, changepw_princ, kr->options); if (kerr != 0) { @@ -1030,9 +1027,7 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) goto sendresponse; }
- memset(pass_str, 0, kr->pd->authtok_size); - talloc_zfree(pass_str); - memset(kr->pd->authtok, 0, kr->pd->authtok_size); + sss_authtok_set_empty(&kr->pd->authtok);
if (kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) { DEBUG(SSSDBG_TRACE_LIBS, @@ -1043,17 +1038,18 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) goto sendresponse; }
- newpass_str = talloc_strndup(kr, (const char *) kr->pd->newauthtok, - kr->pd->newauthtok_size); - if (newpass_str == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); + ret = sss_authtok_get_password(&kr->pd->newauthtok, &newpassword, NULL); + if (ret != EOK) { + DEBUG(1, ("Failed to fetch new password [%d] %s.\n", + ret, strerror(ret))); kerr = KRB5KRB_ERR_GENERIC; goto sendresponse; }
memset(&result_code_string, 0, sizeof(krb5_data)); memset(&result_string, 0, sizeof(krb5_data)); - kerr = krb5_change_password(kr->ctx, kr->creds, newpass_str, &result_code, + kerr = krb5_change_password(kr->ctx, kr->creds, + discard_const(newpassword), &result_code, &result_code_string, &result_string);
if (kerr == KRB5_KDC_UNREACH) { @@ -1109,10 +1105,9 @@ static errno_t changepw_child(int fd, struct krb5_req *kr)
krb5_free_cred_contents(kr->ctx, kr->creds);
- kerr = get_and_save_tgt(kr, newpass_str); - memset(newpass_str, 0, kr->pd->newauthtok_size); - talloc_zfree(newpass_str); - memset(kr->pd->newauthtok, 0, kr->pd->newauthtok_size); + kerr = get_and_save_tgt(kr, newpassword); + + sss_authtok_set_empty(&kr->pd->newauthtok);
pam_status = kerr_to_status(kerr);
@@ -1129,27 +1124,20 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) { int ret; krb5_error_code kerr = 0; - char *pass_str = NULL; + const char *password = NULL; char *changepw_princ = NULL; int pam_status = PAM_SYSTEM_ERR;
DEBUG(SSSDBG_TRACE_LIBS, ("Attempting to get a TGT\n"));
- if (kr->pd->authtok_type != SSS_AUTHTOK_TYPE_PASSWORD) { + ret = sss_authtok_get_password(&kr->pd->authtok, &password, NULL); + if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Unknown authtok type\n")); pam_status = PAM_CRED_INSUFFICIENT; kerr = KRB5KRB_ERR_GENERIC; goto sendresponse; }
- pass_str = talloc_strndup(kr, (const char *) kr->pd->authtok, - kr->pd->authtok_size); - if (pass_str == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - kerr = KRB5KRB_ERR_GENERIC; - goto sendresponse; - } - changepw_princ = talloc_asprintf(kr, "%s@%s", SSSD_KRB5_CHANGEPW_PRINCIPAL, kr->krb5_ctx->realm); if (changepw_princ == NULL) { @@ -1160,7 +1148,7 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) DEBUG(SSSDBG_FUNC_DATA, ("Created a changepw principal [%s]\n", changepw_princ));
- kerr = get_and_save_tgt(kr, pass_str); + kerr = get_and_save_tgt(kr, password);
/* If the password is expired the KDC will always return KRB5KDC_ERR_KEY_EXP regardless if the supplied password is correct or @@ -1176,7 +1164,8 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) DEBUG(1, ("Failed to unset expire callback, continue ...\n")); } kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - pass_str, sss_krb5_prompter, kr, 0, + discard_const(password), + sss_krb5_prompter, kr, 0, changepw_princ, kr->options); krb5_free_cred_contents(kr->ctx, kr->creds); @@ -1185,9 +1174,7 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) } }
- memset(pass_str, 0, kr->pd->authtok_size); - talloc_zfree(pass_str); - memset(kr->pd->authtok, 0, kr->pd->authtok_size); + sss_authtok_set_empty(&kr->pd->authtok);
pam_status = kerr_to_status(kerr);
@@ -1242,25 +1229,20 @@ static errno_t renew_tgt_child(int fd, struct krb5_req *kr) int ret; int status = PAM_AUTHTOK_ERR; int kerr; - char *ccname; + const char *ccname; krb5_ccache ccache = NULL;
DEBUG(SSSDBG_TRACE_LIBS, ("Renewing a ticket\n"));
- if (kr->pd->authtok_type != SSS_AUTHTOK_TYPE_CCFILE) { - DEBUG(1, ("Unsupported authtok type for TGT renewal [%d].\n", - kr->pd->authtok_type)); + ret = sss_authtok_get_ccfile(&kr->pd->authtok, &ccname, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + ("Unsupported authtok type for TGT renewal [%d].\n", + sss_authtok_get_type(&kr->pd->authtok))); kerr = EINVAL; goto done; }
- ccname = talloc_strndup(kr, (char *) kr->pd->authtok, kr->pd->authtok_size); - if (ccname == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - kerr = ENOMEM; - goto done; - } - kerr = krb5_cc_resolve(kr->ctx, ccname, &ccache); if (kerr != 0) { KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); @@ -1353,12 +1335,45 @@ static errno_t create_empty_ccache(int fd, struct krb5_req *kr) return ret; }
+static errno_t unpack_authtok(TALLOC_CTX *mem_ctx, struct sss_auth_token *tok, + uint8_t *buf, size_t size, size_t *p) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + errno_t ret = EOK; + + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, buf + *p, size, p); + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_length, buf + *p, size, p); + if ((*p + auth_token_length) > size) { + return EINVAL; + } + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_set_password(mem_ctx, tok, (char *)(buf + *p), 0); + break; + case SSS_AUTHTOK_TYPE_CCFILE: + ret = sss_authtok_set_ccfile(mem_ctx, tok, (char *)(buf + *p)); + break; + default: + return EINVAL; + } + + if (ret == EOK) { + *p += auth_token_length; + } + return ret; +} + static errno_t unpack_buffer(uint8_t *buf, size_t size, struct pam_data *pd, struct krb5_req *kr, uint32_t *offline) { size_t p = 0; uint32_t len; uint32_t validate; + errno_t ret;
DEBUG(SSSDBG_TRACE_LIBS, ("total buffer size: [%d]\n", size));
@@ -1397,35 +1412,26 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size, struct pam_data *pd, if (kr->keytab == NULL) return ENOMEM; p += len;
- SAFEALIGN_COPY_UINT32_CHECK(&pd->authtok_type, buf + p, size, &p); - SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p); - if ((p + len) > size) return EINVAL; - pd->authtok = (uint8_t *)talloc_strndup(pd, (char *)(buf + p), len); - if (pd->authtok == NULL) return ENOMEM; - pd->authtok_size = len + 1; - p += len; + ret = unpack_authtok(pd, &pd->authtok, buf, size, &p); + if (ret) { + return ret; + }
DEBUG(SSSDBG_CONF_SETTINGS, ("ccname: [%s] keytab: [%s]\n", kr->ccname, kr->keytab)); } else { kr->ccname = NULL; kr->keytab = NULL; - pd->authtok = NULL; - pd->authtok_size = 0; + sss_authtok_set_empty(&pd->authtok); }
if (pd->cmd == SSS_PAM_CHAUTHTOK) { - SAFEALIGN_COPY_UINT32_CHECK(&pd->newauthtok_type, buf + p, size, &p); - SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p); - - if ((p + len) > size) return EINVAL; - pd->newauthtok = (uint8_t *)talloc_strndup(pd, (char *)(buf + p), len); - if (pd->newauthtok == NULL) return ENOMEM; - pd->newauthtok_size = len + 1; - p += len; + ret = unpack_authtok(pd, &pd->newauthtok, buf, size, &p); + if (ret) { + return ret; + } } else { - pd->newauthtok = NULL; - pd->newauthtok_size = 0; + sss_authtok_set_empty(&pd->newauthtok); }
if (pd->cmd == SSS_PAM_ACCT_MGMT) { diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c index 768d8c7dce1a8dd20b471f6abb51b16d2da4563b..c73211cbdf0323bc2c2a8184592e0127f90a8efc 100644 --- a/src/providers/krb5/krb5_child_handler.c +++ b/src/providers/krb5/krb5_child_handler.c @@ -85,6 +85,43 @@ static int child_io_destructor(void *ptr) return EOK; }
+static errno_t pack_authtok(struct io_buffer *buf, size_t *rp, + struct sss_auth_token *tok) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + const char *data; + size_t len; + errno_t ret = EOK; + + auth_token_type = sss_authtok_get_type(tok); + + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + auth_token_length = 0; + data = ""; + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_get_password(tok, &data, &len); + auth_token_length = len + 1; + break; + case SSS_AUTHTOK_TYPE_CCFILE: + ret = sss_authtok_get_password(tok, &data, &len); + auth_token_length = len + 1; + break; + default: + ret = EINVAL; + } + + if (ret == EOK) { + SAFEALIGN_COPY_UINT32(&buf->data[*rp], &auth_token_type, rp); + SAFEALIGN_COPY_UINT32(&buf->data[*rp], &auth_token_length, rp); + safealign_memcpy(&buf->data[*rp], data, auth_token_length, rp); + } + + return ret; +} + static errno_t create_send_buffer(struct krb5child_req *kr, struct io_buffer **io_buf) { @@ -93,6 +130,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr, const char *keytab; uint32_t validate; size_t username_len = 0; + errno_t ret;
keytab = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_KEYTAB); if (keytab == NULL) { @@ -115,11 +153,12 @@ static errno_t create_send_buffer(struct krb5child_req *kr, kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM || kr->pd->cmd == SSS_PAM_CHAUTHTOK) { buf->size += 4*sizeof(uint32_t) + strlen(kr->ccname) + strlen(keytab) + - kr->pd->authtok_size; + sss_authtok_get_size(&kr->pd->authtok); }
if (kr->pd->cmd == SSS_PAM_CHAUTHTOK) { - buf->size += 2*sizeof(uint32_t) + kr->pd->newauthtok_size; + buf->size += 2*sizeof(uint32_t) + + sss_authtok_get_size(&kr->pd->newauthtok); }
if (kr->pd->cmd == SSS_PAM_ACCT_MGMT) { @@ -154,17 +193,17 @@ static errno_t create_send_buffer(struct krb5child_req *kr, SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(keytab), &rp); safealign_memcpy(&buf->data[rp], keytab, strlen(keytab), &rp);
- SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->authtok_type, &rp); - SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->authtok_size, &rp); - safealign_memcpy(&buf->data[rp], kr->pd->authtok, - kr->pd->authtok_size, &rp); + ret = pack_authtok(buf, &rp, &kr->pd->authtok); + if (ret) { + return ret; + } }
if (kr->pd->cmd == SSS_PAM_CHAUTHTOK) { - SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->newauthtok_type, &rp); - SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->newauthtok_size, &rp); - safealign_memcpy(&buf->data[rp], kr->pd->newauthtok, - kr->pd->newauthtok_size, &rp); + ret = pack_authtok(buf, &rp, &kr->pd->newauthtok); + if (ret) { + return ret; + } }
if (kr->pd->cmd == SSS_PAM_ACCT_MGMT) { diff --git a/src/providers/krb5/krb5_delayed_online_authentication.c b/src/providers/krb5/krb5_delayed_online_authentication.c index d5dea3bb4c7661f45b6bea83cf803c7d681062cc..f95fa634c34ebee37bffb785abe4ef5b35318a82 100644 --- a/src/providers/krb5/krb5_delayed_online_authentication.c +++ b/src/providers/krb5/krb5_delayed_online_authentication.c @@ -71,27 +71,29 @@ static void authenticate_user(struct tevent_context *ev,
DEBUG_PAM_DATA(9, pd);
- if (pd->authtok == NULL || pd->authtok_size == 0) { - DEBUG(1, ("Missing authtok for user [%s].\n", pd->user)); - return; - } - #ifdef USE_KEYRING + char *password; long keysize; long keyrevoke; - int ret; - keysize = keyctl_read(pd->key_serial, (char *) pd->authtok, - pd->authtok_size); - keyrevoke = keyctl_revoke(pd->key_serial); + errno_t ret; + + keysize = keyctl_read_alloc(pd->key_serial, (void **)&password); if (keysize == -1) { ret = errno; DEBUG(1, ("keyctl_read failed [%d][%s].\n", ret, strerror(ret))); return; - } else if (keysize != pd->authtok_size) { - DEBUG(1, ("keyctl_read returned key with wrong size, " - "expect [%d] got [%d].\n", pd->authtok_size, keysize)); + } + + ret = sss_authtok_set_password(pd, &pd->authtok, password, keysize); + safezero(password, keysize); + free(password); + if (ret) { + DEBUG(1, ("failed to set password in auth token [%d][%s].\n", + ret, strerror(ret))); return; } + + keyrevoke = keyctl_revoke(pd->key_serial); if (keyrevoke == -1) { ret = errno; DEBUG(1, ("keyctl_revoke failed [%d][%s].\n", ret, strerror(ret))); @@ -244,8 +246,8 @@ errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx, return EINVAL; }
- if (pd->authtok_size == 0 || pd->authtok == NULL) { - DEBUG(1, ("Missing authtok for user [%s].\n", pd->user)); + if (sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { + DEBUG(1, ("Invalid authtok for user [%s].\n", pd->user)); return EINVAL; }
@@ -257,17 +259,29 @@ errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx,
#ifdef USE_KEYRING - new_pd->key_serial = add_key("user", new_pd->user, new_pd->authtok, - new_pd->authtok_size, KEY_SPEC_SESSION_KEYRING); + const char *password; + size_t len; + + ret = sss_authtok_get_password(&new_pd->authtok, &password, &len); + if (ret) { + DEBUG(1, ("Failed to get password [%d][%s].\n", ret, strerror(ret))); + sss_authtok_set_empty(&new_pd->authtok); + talloc_free(new_pd); + return ret; + } + + new_pd->key_serial = add_key("user", new_pd->user, password, len, + KEY_SPEC_SESSION_KEYRING); if (new_pd->key_serial == -1) { ret = errno; - DEBUG(1, ("add_key fialed [%d][%s].\n", ret, strerror(ret))); + DEBUG(1, ("add_key failed [%d][%s].\n", ret, strerror(ret))); + sss_authtok_set_empty(&new_pd->authtok); talloc_free(new_pd); return ret; } DEBUG(9, ("Saved authtok of user [%s] with serial [%ld].\n", new_pd->user, new_pd->key_serial)); - memset(new_pd->authtok, 0, new_pd->authtok_size); + sss_authtok_set_empty(&new_pd->authtok); #endif
key.type = HASH_KEY_ULONG; diff --git a/src/providers/krb5/krb5_renew_tgt.c b/src/providers/krb5/krb5_renew_tgt.c index 2ad5592e9ca6e4943c55d302093ed638ae2951a4..3d5b5e66e0ce143f986867842fc418ba333893de 100644 --- a/src/providers/krb5/krb5_renew_tgt.c +++ b/src/providers/krb5/krb5_renew_tgt.c @@ -565,22 +565,14 @@ errno_t add_tgt_to_renew_table(struct krb5_ctx *krb5_ctx, const char *ccfile, goto done; }
- if (renew_data->pd->newauthtok_type != SSS_AUTHTOK_TYPE_EMPTY) { - talloc_zfree(renew_data->pd->newauthtok); - renew_data->pd->newauthtok_size = 0; - renew_data->pd->newauthtok_type = SSS_AUTHTOK_TYPE_EMPTY; - } + sss_authtok_set_empty(&renew_data->pd->newauthtok);
- talloc_zfree(renew_data->pd->authtok); - renew_data->pd->authtok = (uint8_t *) talloc_strdup(renew_data->pd, - renew_data->ccfile); - if (renew_data->pd->authtok == NULL) { - DEBUG(1, ("talloc_strdup failed.\n")); - ret = ENOMEM; + ret = sss_authtok_set_ccfile(renew_data->pd, + &renew_data->pd->authtok, renew_data->ccfile); + if (ret) { + DEBUG(1, ("Failed to store ccfile in auth token.\n")); goto done; } - renew_data->pd->authtok_size = strlen((char *) renew_data->pd->authtok) + 1; - renew_data->pd->authtok_type = SSS_AUTHTOK_TYPE_CCFILE;
renew_data->pd->cmd = SSS_CMD_RENEW;
diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c index 32a2e04ea959a3cc81b88f5b2b19575c813e8adf..98483fee0da418523e78152861d489988eb9c6c2 100644 --- a/src/providers/ldap/ldap_auth.c +++ b/src/providers/ldap/ldap_auth.c @@ -462,7 +462,7 @@ struct auth_state { struct tevent_context *ev; struct sdap_auth_ctx *ctx; const char *username; - struct dp_opt_blob password; + struct sss_auth_token *authtok; struct sdap_service *sdap_service;
struct sdap_handle *sh; @@ -484,7 +484,7 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx, struct tevent_context *ev, struct sdap_auth_ctx *ctx, const char *username, - struct dp_opt_blob password, + struct sss_auth_token *authtok, bool try_chpass_service) { struct tevent_req *req; @@ -493,8 +493,8 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx, req = tevent_req_create(memctx, &state, struct auth_state); if (!req) return NULL;
- /* Treat a zero-length password as a failure */ - if (password.length == 0) { + /* The token must be a password token */ + if (sss_authtok_get_type(authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { state->result = SDAP_AUTH_FAILED; tevent_req_done(req); return tevent_req_post(req, ev); @@ -503,7 +503,7 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx, state->ev = ev; state->ctx = ctx; state->username = username; - state->password = password; + state->authtok = authtok; state->srv = NULL; if (try_chpass_service && ctx->chpass_service != NULL && ctx->chpass_service->name != NULL) { @@ -632,7 +632,7 @@ static void auth_connect_done(struct tevent_req *subreq)
subreq = sdap_auth_send(state, state->ev, state->sh, NULL, NULL, state->dn, - "password", state->password); + state->authtok); if (!subreq) { tevent_req_error(req, ENOMEM); return; @@ -727,8 +727,6 @@ struct sdap_pam_chpass_state { struct pam_data *pd; const char *username; char *dn; - char *password; - char *new_password; struct sdap_handle *sh;
struct sdap_auth_ctx *ctx; @@ -744,7 +742,6 @@ void sdap_pam_chpass_handler(struct be_req *breq) struct sdap_auth_ctx *ctx; struct tevent_req *subreq; struct pam_data *pd; - struct dp_opt_blob authtok; int dp_err = DP_ERR_FATAL;
ctx = talloc_get_type(breq->be_ctx->bet_info[BET_CHPASS].pvt_bet_data, @@ -758,8 +755,8 @@ void sdap_pam_chpass_handler(struct be_req *breq) goto done; }
- if (pd->priv == 1 && pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM && - pd->authtok_size == 0) { + if ((pd->priv == 1) && (pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) && + (sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD)) { DEBUG(4, ("Password reset by root is not supported.\n")); pd->pam_status = PAM_PERM_DENIED; dp_err = DP_ERR_OK; @@ -782,25 +779,9 @@ void sdap_pam_chpass_handler(struct be_req *breq) state->pd = pd; state->username = pd->user; state->ctx = ctx; - state->password = talloc_strndup(state, - (char *)pd->authtok, pd->authtok_size); - if (!state->password) goto done; - talloc_set_destructor((TALLOC_CTX *)state->password, - password_destructor);
- if (pd->cmd == SSS_PAM_CHAUTHTOK) { - state->new_password = talloc_strndup(state, - (char *)pd->newauthtok, - pd->newauthtok_size); - if (!state->new_password) goto done; - talloc_set_destructor((TALLOC_CTX *)state->new_password, - password_destructor); - } - - authtok.data = (uint8_t *)state->password; - authtok.length = strlen(state->password); - subreq = auth_send(breq, breq->be_ctx->ev, - ctx, state->username, authtok, true); + subreq = auth_send(breq, breq->be_ctx->ev, ctx, + state->username, &pd->authtok, true); if (!subreq) goto done;
tevent_req_set_callback(subreq, sdap_auth4chpass_done, state); @@ -887,18 +868,30 @@ static void sdap_auth4chpass_done(struct tevent_req *req) state->pd->pam_status = PAM_MODULE_UNKNOWN; goto done; } else { + const char *password; + const char *new_password; + + ret = sss_authtok_get_password(&state->pd->authtok, + &password, NULL); + if (ret) { + state->pd->pam_status = PAM_SYSTEM_ERR; + goto done; + } + ret = sss_authtok_get_password(&state->pd->newauthtok, + &new_password, NULL); + if (ret) { + state->pd->pam_status = PAM_SYSTEM_ERR; + goto done; + } + subreq = sdap_exop_modify_passwd_send(state, state->breq->be_ctx->ev, - state->sh, - state->dn, - state->password, - state->new_password); - + state->sh, state->dn, + password, new_password); if (!subreq) { DEBUG(2, ("Failed to change password for %s\n", state->username)); goto done; } - tevent_req_set_callback(subreq, sdap_pam_chpass_done, state); return; } @@ -1013,8 +1006,6 @@ done: struct sdap_pam_auth_state { struct be_req *breq; struct pam_data *pd; - const char *username; - struct dp_opt_blob password; };
static void sdap_pam_auth_done(struct tevent_req *req); @@ -1049,12 +1040,9 @@ void sdap_pam_auth_handler(struct be_req *breq)
state->breq = breq; state->pd = pd; - state->username = pd->user; - state->password.data = pd->authtok; - state->password.length = pd->authtok_size;
subreq = auth_send(breq, breq->be_ctx->ev, ctx, - state->username, state->password, + pd->user, &pd->authtok, pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM ? true : false); if (!subreq) goto done;
@@ -1088,6 +1076,7 @@ static void sdap_pam_auth_done(struct tevent_req *req) enum pwexpire pw_expire_type; struct be_ctx *be_ctx = state->breq->be_ctx; void *pw_expire_data; + const char *password; int dp_err = DP_ERR_OK; int ret;
@@ -1170,26 +1159,19 @@ static void sdap_pam_auth_done(struct tevent_req *req) if (result == SDAP_AUTH_SUCCESS && state->breq->be_ctx->domain->cache_credentials) {
- char *password = talloc_strndup(state, (char *) - state->password.data, - state->password.length); - /* password caching failures are not fatal errors */ - if (!password) { - DEBUG(2, ("Failed to cache password for %s\n", state->username)); - goto done; + ret = sss_authtok_get_password(&state->pd->authtok, &password, NULL); + if (ret == EOK) { + ret = sysdb_cache_password(state->breq->be_ctx->sysdb, + state->pd->user, password); } - talloc_set_destructor((TALLOC_CTX *)password, password_destructor); - - ret = sysdb_cache_password(state->breq->be_ctx->sysdb, - state->username, password);
/* password caching failures are not fatal errors */ if (ret != EOK) { DEBUG(2, ("Failed to cache password for %s\n", - state->username)); + state->pd->user)); } else { DEBUG(4, ("Password successfully cached for %s\n", - state->username)); + state->pd->user)); } goto done; } diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c index e0440625d279fbbaa1cc2e6343b73f5a247371f7..84497b75ef586b58e27cc4dc9e6b8b3244464676 100644 --- a/src/providers/ldap/sdap_async.c +++ b/src/providers/ldap/sdap_async.c @@ -502,8 +502,8 @@ struct tevent_req *sdap_exop_modify_passwd_send(TALLOC_CTX *memctx, struct tevent_context *ev, struct sdap_handle *sh, char *user_dn, - char *password, - char *new_password) + const char *password, + const char *new_password) { struct tevent_req *req = NULL; struct sdap_exop_modify_passwd_state *state; diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h index 8c16d94e6486336e92b6112cd8b5a2dff4c97957..c5dc17037cd6d2c4ae88aa60d43d517eb2958085 100644 --- a/src/providers/ldap/sdap_async.h +++ b/src/providers/ldap/sdap_async.h @@ -108,8 +108,7 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, const char *sasl_mech, const char *sasl_user, const char *user_dn, - const char *authtok_type, - struct dp_opt_blob authtok); + struct sss_auth_token *authtok);
int sdap_auth_recv(struct tevent_req *req, TALLOC_CTX *memctx, @@ -128,8 +127,8 @@ struct tevent_req *sdap_exop_modify_passwd_send(TALLOC_CTX *memctx, struct tevent_context *ev, struct sdap_handle *sh, char *user_dn, - char *password, - char *new_password); + const char *password, + const char *new_password); int sdap_exop_modify_passwd_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, enum sdap_result *result, char **user_error_msg); diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c index 79ad3b8e4c7720982944e502c4424d61dd1f1295..c8d7f2487c79932b642a96fb2c56569075f2d774 100644 --- a/src/providers/ldap/sdap_async_connection.c +++ b/src/providers/ldap/sdap_async_connection.c @@ -493,7 +493,7 @@ static struct tevent_req *simple_bind_send(TALLOC_CTX *memctx, DEBUG(4, ("Executing simple bind as: %s\n", state->user_dn));
ret = ldap_sasl_bind(state->sh->ldap, state->user_dn, LDAP_SASL_SIMPLE, - state->pw, request_controls, NULL, &msgid); + pw, request_controls, NULL, &msgid); if (ctrls[0]) ldap_control_free(ctrls[0]); if (ret == -1 || msgid == -1) { ret = ldap_get_option(state->sh->ldap, @@ -1082,18 +1082,12 @@ int sdap_kinit_recv(struct tevent_req *req, /* ==Authenticaticate-User-by-DN========================================== */
struct sdap_auth_state { - const char *user_dn; - struct berval pw; struct sdap_ppolicy_data *ppolicy; - - int result; bool is_sasl; + int result; };
static void sdap_auth_done(struct tevent_req *subreq); -static int sdap_auth_get_authtok(const char *authtok_type, - struct dp_opt_blob authtok, - struct berval *pw);
/* TODO: handle sasl_cred */ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, @@ -1102,31 +1096,14 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, const char *sasl_mech, const char *sasl_user, const char *user_dn, - const char *authtok_type, - struct dp_opt_blob authtok) + struct sss_auth_token *authtok) { struct tevent_req *req, *subreq; struct sdap_auth_state *state; - int ret;
req = tevent_req_create(memctx, &state, struct sdap_auth_state); if (!req) return NULL;
- state->user_dn = user_dn; - - ret = sdap_auth_get_authtok(authtok_type, authtok, &state->pw); - if (ret != EOK) { - if (ret == ENOSYS) { - DEBUG(1, ("Getting authtok is not supported with the " - "crypto library compiled with, authentication " - "might fail!\n")); - } else { - DEBUG(1, ("Cannot parse authtok.\n")); - tevent_req_error(req, ret); - return tevent_req_post(req, ev); - } - } - if (sasl_mech) { state->is_sasl = true; subreq = sasl_bind_send(state, ev, sh, sasl_mech, sasl_user, NULL); @@ -1135,8 +1112,27 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, return tevent_req_post(req, ev); } } else { + const char *password = NULL; + struct berval pw; + size_t pwlen; + errno_t ret; + + ret = sss_authtok_get_password(authtok, &password, &pwlen); + if (ret != EOK) { + DEBUG(1, ("Cannot parse authtok.\n")); + tevent_req_error(req, ret); + return tevent_req_post(req, ev); + } + /* Treat a zero-length password as a failure */ + if (*password == '\0') { + tevent_req_error(req, ENOENT); + return tevent_req_post(req, ev); + } + pw.bv_val = discard_const(password); + pw.bv_len = pwlen - 1; + state->is_sasl = false; - subreq = simple_bind_send(state, ev, sh, user_dn, &state->pw); + subreq = simple_bind_send(state, ev, sh, user_dn, &pw); if (!subreq) { tevent_req_error(req, ENOMEM); return tevent_req_post(req, ev); @@ -1598,6 +1594,10 @@ static void sdap_cli_auth_step(struct tevent_req *req) SDAP_SASL_MECH); const char *user_dn = dp_opt_get_string(state->opts->basic, SDAP_DEFAULT_BIND_DN); + const char *authtok_type; + struct dp_opt_blob authtok_blob; + struct sss_auth_token authtok; + errno_t ret;
if (!state->do_auth || (sasl_mech == NULL && user_dn == NULL)) { @@ -1617,17 +1617,28 @@ static void sdap_cli_auth_step(struct tevent_req *req) state->sh->expire_time = now + expire_timeout; }
- subreq = sdap_auth_send(state, - state->ev, - state->sh, - sasl_mech, + authtok_type = dp_opt_get_string(state->opts->basic, + SDAP_DEFAULT_AUTHTOK_TYPE); + if (strcasecmp(authtok_type, "password") != 0) { + DEBUG(SSSDBG_TRACE_LIBS, ("Invalid authtoken type\n")); + tevent_req_error(req, EINVAL); + return; + } + authtok_blob = dp_opt_get_blob(state->opts->basic, SDAP_DEFAULT_AUTHTOK); + + ret = sss_authtok_set_password(NULL, &authtok, + (const char *)authtok_blob.data, + authtok_blob.length); + if (ret) { + tevent_req_error(req, ret); + return; + } + + subreq = sdap_auth_send(state, state->ev, + state->sh, sasl_mech, dp_opt_get_string(state->opts->basic, - SDAP_SASL_AUTHID), - user_dn, - dp_opt_get_string(state->opts->basic, - SDAP_DEFAULT_AUTHTOK_TYPE), - dp_opt_get_blob(state->opts->basic, - SDAP_DEFAULT_AUTHTOK)); + SDAP_SASL_AUTHID), + user_dn, &authtok); if (!subreq) { tevent_req_error(req, ENOMEM); return; diff --git a/src/providers/proxy/proxy.h b/src/providers/proxy/proxy.h index cea03382517231cdf2b96069ab93dfb7967b46a6..962cb28fc7d6362c45d268f289ffbce103a6e738 100644 --- a/src/providers/proxy/proxy.h +++ b/src/providers/proxy/proxy.h @@ -89,11 +89,8 @@ struct proxy_nss_ops { };
struct authtok_conv { - uint32_t authtok_size; - uint8_t *authtok; - - uint32_t newauthtok_size; - uint8_t *newauthtok; + struct sss_auth_token authtok; + struct sss_auth_token newauthtok;
bool sent_old; }; diff --git a/src/providers/proxy/proxy_auth.c b/src/providers/proxy/proxy_auth.c index 8088283fa8147f75b7d8eb4c83c63208163c9375..3430f38b282eff2da24735f8d635a952edde8888 100644 --- a/src/providers/proxy/proxy_auth.c +++ b/src/providers/proxy/proxy_auth.c @@ -712,7 +712,7 @@ static void proxy_child_done(struct tevent_req *req) struct proxy_client_ctx *client_ctx = tevent_req_callback_data(req, struct proxy_client_ctx); struct pam_data *pd = NULL; - char *password; + const char *password; int ret; struct tevent_immediate *imm;
@@ -747,17 +747,15 @@ static void proxy_child_done(struct tevent_req *req)
/* Check if we need to save the cached credentials */ if ((pd->cmd == SSS_PAM_AUTHENTICATE || pd->cmd == SSS_PAM_CHAUTHTOK) && - pd->pam_status == PAM_SUCCESS && - client_ctx->be_req->be_ctx->domain->cache_credentials) { - password = talloc_strndup(client_ctx->be_req, - (char *) pd->authtok, - pd->authtok_size); - if (!password) { + (pd->pam_status == PAM_SUCCESS) && + client_ctx->be_req->be_ctx->domain->cache_credentials) { + + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + if (ret) { /* password caching failures are not fatal errors */ DEBUG(2, ("Failed to cache password\n")); goto done; } - talloc_set_destructor((TALLOC_CTX *)password, password_destructor);
ret = sysdb_cache_password(client_ctx->be_req->be_ctx->sysdb, pd->user, password); diff --git a/src/providers/proxy/proxy_child.c b/src/providers/proxy/proxy_child.c index 8aa1d76273b8464de8e5e2d96f65dd56a5933fdd..f8ffee0402f8396173063736c50608e0f455d032 100644 --- a/src/providers/proxy/proxy_child.c +++ b/src/providers/proxy/proxy_child.c @@ -80,6 +80,9 @@ static int proxy_internal_conv(int num_msg, const struct pam_message **msgm, int i; struct pam_response *reply; struct authtok_conv *auth_data; + const char *password; + size_t pwlen; + errno_t ret;
auth_data = talloc_get_type(appdata_ptr, struct authtok_conv);
@@ -94,11 +97,13 @@ static int proxy_internal_conv(int num_msg, const struct pam_message **msgm, case PAM_PROMPT_ECHO_OFF: DEBUG(4, ("Conversation message: [%s]\n", msgm[i]->msg)); reply[i].resp_retcode = 0; - reply[i].resp = calloc(auth_data->authtok_size + 1, - sizeof(char)); + + ret = sss_authtok_get_password(&auth_data->authtok, + &password, &pwlen); + if (ret) goto failed; + reply[i].resp = calloc(pwlen + 1, sizeof(char)); if (reply[i].resp == NULL) goto failed; - memcpy(reply[i].resp, auth_data->authtok, - auth_data->authtok_size); + memcpy(reply[i].resp, password, pwlen + 1);
break; default: @@ -124,6 +129,9 @@ static int proxy_chauthtok_conv(int num_msg, const struct pam_message **msgm, int i; struct pam_response *reply; struct authtok_conv *auth_data; + const char *password; + size_t pwlen; + errno_t ret;
auth_data = talloc_get_type(appdata_ptr, struct authtok_conv);
@@ -141,20 +149,23 @@ static int proxy_chauthtok_conv(int num_msg, const struct pam_message **msgm, reply[i].resp_retcode = 0; if (!auth_data->sent_old) { /* The first prompt will be asking for the old authtok */ - reply[i].resp = calloc(auth_data->authtok_size + 1, - sizeof(char)); + ret = sss_authtok_get_password(&auth_data->authtok, + &password, &pwlen); + if (ret) goto failed; + reply[i].resp = calloc(pwlen + 1, sizeof(char)); if (reply[i].resp == NULL) goto failed; - memcpy(reply[i].resp, auth_data->authtok, - auth_data->authtok_size); + memcpy(reply[i].resp, password, pwlen + 1); auth_data->sent_old = true; } else { /* Subsequent prompts are looking for the new authtok */ - reply[i].resp = calloc(auth_data->newauthtok_size + 1, - sizeof(char)); + ret = sss_authtok_get_password(&auth_data->newauthtok, + &password, &pwlen); + if (ret) goto failed; + reply[i].resp = calloc(pwlen + 1, sizeof(char)); if (reply[i].resp == NULL) goto failed; - memcpy(reply[i].resp, auth_data->newauthtok, - auth_data->newauthtok_size); + memcpy(reply[i].resp, password, pwlen + 1); + auth_data->sent_old = true; }
break; @@ -213,8 +224,8 @@ static errno_t call_pam_stack(const char *pam_target, struct pam_data *pd) } switch (pd->cmd) { case SSS_PAM_AUTHENTICATE: - auth_data->authtok_size = pd->authtok_size; - auth_data->authtok = pd->authtok; + sss_authtok_copy(auth_data, &pd->authtok, + &auth_data->authtok); pam_status = pam_authenticate(pamh, 0); break; case SSS_PAM_SETCRED: @@ -230,21 +241,21 @@ static errno_t call_pam_stack(const char *pam_target, struct pam_data *pd) pam_status=pam_close_session(pamh, 0); break; case SSS_PAM_CHAUTHTOK: - auth_data->authtok_size = pd->authtok_size; - auth_data->authtok = pd->authtok; + sss_authtok_copy(auth_data, &pd->authtok, + &auth_data->authtok); if (pd->priv != 1) { pam_status = pam_authenticate(pamh, 0); auth_data->sent_old = false; if (pam_status != PAM_SUCCESS) break; } - auth_data->newauthtok_size = pd->newauthtok_size; - auth_data->newauthtok = pd->newauthtok; + sss_authtok_copy(auth_data, &pd->newauthtok, + &auth_data->newauthtok); pam_status = pam_chauthtok(pamh, 0); break; case SSS_PAM_CHAUTHTOK_PRELIM: if (pd->priv != 1) { - auth_data->authtok_size = pd->authtok_size; - auth_data->authtok = pd->authtok; + sss_authtok_copy(auth_data, &pd->authtok, + &auth_data->authtok); pam_status = pam_authenticate(pamh, 0); } else { pam_status = PAM_SUCCESS; diff --git a/src/responder/pam/pam_LOCAL_domain.c b/src/responder/pam/pam_LOCAL_domain.c index 71446b4f8da53bfe4c0707621fafb228da5f808c..23eb7a2a8ddd3ae4480030633be867564b7f59f2 100644 --- a/src/responder/pam/pam_LOCAL_domain.c +++ b/src/responder/pam/pam_LOCAL_domain.c @@ -154,22 +154,19 @@ static void do_pam_acct_mgmt(struct LOCAL_request *lreq) static void do_pam_chauthtok(struct LOCAL_request *lreq) { int ret; - char *newauthtok; + const char *password; char *salt; char *new_hash; struct pam_data *pd;
pd = lreq->preq->pd;
- newauthtok = talloc_strndup(lreq, (char *) pd->newauthtok, - pd->newauthtok_size); - NULL_CHECK_OR_JUMP(newauthtok, ("talloc_strndup failed.\n"), lreq->error, - ENOMEM, done); - memset(pd->newauthtok, 0, pd->newauthtok_size); - - if (strlen(newauthtok) == 0) { + ret = sss_authtok_get_password(&pd->newauthtok, &password, NULL); + if (ret) { /* TODO: should we allow null passwords via a config option ? */ - DEBUG(1, ("Empty passwords are not allowed!\n")); + if (ret == ENOENT) { + DEBUG(1, ("Empty passwords are not allowed!\n")); + } lreq->error = EINVAL; goto done; } @@ -179,11 +176,10 @@ static void do_pam_chauthtok(struct LOCAL_request *lreq) lreq->error, ret, done); DEBUG(4, ("Using salt [%s]\n", salt));
- ret = s3crypt_sha512(lreq, newauthtok, salt, &new_hash); + ret = s3crypt_sha512(lreq, password, salt, &new_hash); NEQ_CHECK_OR_JUMP(ret, EOK, ("Hash generation failed.\n"), lreq->error, ret, done); DEBUG(4, ("New hash [%s]\n", new_hash)); - memset(newauthtok, 0, pd->newauthtok_size);
lreq->mod_attrs = sysdb_new_attrs(lreq); NULL_CHECK_OR_JUMP(lreq->mod_attrs, ("sysdb_new_attrs failed.\n"), @@ -204,7 +200,7 @@ static void do_pam_chauthtok(struct LOCAL_request *lreq) lreq->error, ret, done);
done: - return; + sss_authtok_set_empty(&pd->newauthtok); }
int LOCAL_pam_handler(struct pam_auth_req *preq) @@ -223,9 +219,9 @@ int LOCAL_pam_handler(struct pam_auth_req *preq) NULL}; struct ldb_result *res; const char *username = NULL; - const char *password = NULL; + const char *pwdhash = NULL; char *new_hash = NULL; - char *authtok = NULL; + const char *password; struct pam_data *pd = preq->pd; int ret;
@@ -287,25 +283,22 @@ int LOCAL_pam_handler(struct pam_auth_req *preq) DEBUG(4, ("allowing root to reset a password.\n")); break; } - authtok = talloc_strndup(lreq, (char *) pd->authtok, - pd->authtok_size); - NULL_CHECK_OR_JUMP(authtok, ("talloc_strndup failed.\n"), - lreq->error, ENOMEM, done); - memset(pd->authtok, 0, pd->authtok_size); + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + NEQ_CHECK_OR_JUMP(ret, EOK, ("Failed to get password.\n"), + lreq->error, ret, done);
- password = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_PWD, NULL); - NULL_CHECK_OR_JUMP(password, ("No password stored.\n"), + pwdhash = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_PWD, NULL); + NULL_CHECK_OR_JUMP(pwdhash, ("No password stored.\n"), lreq->error, LDB_ERR_NO_SUCH_ATTRIBUTE, done); - DEBUG(4, ("user: [%s], password hash: [%s]\n", username, password)); + DEBUG(4, ("user: [%s], password hash: [%s]\n", username, pwdhash));
- ret = s3crypt_sha512(lreq, authtok, password, &new_hash); - memset(authtok, 0, pd->authtok_size); + ret = s3crypt_sha512(lreq, password, pwdhash, &new_hash); NEQ_CHECK_OR_JUMP(ret, EOK, ("nss_sha512_crypt failed.\n"), lreq->error, ret, done);
DEBUG(4, ("user: [%s], new hash: [%s]\n", username, new_hash));
- if (strcmp(new_hash, password) != 0) { + if (strcmp(new_hash, pwdhash) != 0) { DEBUG(1, ("Passwords do not match.\n")); do_failed_login(lreq); goto done; @@ -338,13 +331,8 @@ int LOCAL_pam_handler(struct pam_auth_req *preq) }
done: - if (pd->authtok != NULL) - memset(pd->authtok, 0, pd->authtok_size); - if (authtok != NULL) - memset(authtok, 0, pd->authtok_size); - if (pd->newauthtok != NULL) - memset(pd->newauthtok, 0, pd->newauthtok_size); - + sss_authtok_set_empty(&pd->newauthtok); + sss_authtok_set_empty(&pd->authtok); prepare_reply(lreq); return EOK; } diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index 8ab90e30e3f553c95a43db3ce69799b8b6d24d76..689155fa32bbf63f707c9d830d46cf586c940bbf 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -48,21 +48,38 @@ enum pam_verbosity {
static void pam_reply(struct pam_auth_req *preq);
-static int extract_authtok(uint32_t *type, uint32_t *size, uint8_t **tok, - size_t data_size, uint8_t *body, size_t blen, - size_t *c) { +static int extract_authtok_v2(TALLOC_CTX *mem_ctx, struct sss_auth_token *tok, + size_t data_size, uint8_t *body, size_t blen, + size_t *c) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + uint8_t *auth_token_data; + int ret = EOK;
if (data_size < sizeof(uint32_t) || *c+data_size > blen || SIZE_T_OVERFLOW(*c, data_size)) return EINVAL; - *size = data_size - sizeof(uint32_t);
- SAFEALIGN_COPY_UINT32_CHECK(type, &body[*c], blen, c); + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, &body[*c], blen, c); + auth_token_length = data_size - sizeof(uint32_t); + auth_token_data = body+(*c);
- *tok = body+(*c); + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_set_password(mem_ctx, tok, + (const char *)auth_token_data, + auth_token_length); + break; + default: + return EINVAL; + }
- *c += (*size); + *c += auth_token_length;
- return EOK; + return ret; }
static int extract_string(char **var, size_t size, uint8_t *body, size_t blen, @@ -184,14 +201,13 @@ static int pam_parse_in_data_v2(struct sss_domain_info *domains, if (ret != EOK) return ret; break; case SSS_PAM_ITEM_AUTHTOK: - ret = extract_authtok(&pd->authtok_type, &pd->authtok_size, - &pd->authtok, size, body, blen, &c); + ret = extract_authtok_v2(pd, &pd->authtok, + size, body, blen, &c); if (ret != EOK) return ret; break; case SSS_PAM_ITEM_NEWAUTHTOK: - ret = extract_authtok(&pd->newauthtok_type, - &pd->newauthtok_size, - &pd->newauthtok, size, body, blen, &c); + ret = extract_authtok_v2(pd, &pd->newauthtok, + size, body, blen, &c); if (ret != EOK) return ret; break; default: @@ -231,14 +247,44 @@ static int pam_parse_in_data_v3(struct sss_domain_info *domains, return EOK; }
+static int extract_authtok_v1(TALLOC_CTX *mem_ctx, struct sss_auth_token *tok, + uint8_t *body, size_t blen, size_t *c) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + uint8_t *auth_token_data; + int ret = EOK; + + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, &body[*c], blen, c); + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_length, &body[*c], blen, c); + auth_token_data = body+(*c); + + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_set_password(mem_ctx, tok, + (const char *)auth_token_data, + auth_token_length); + break; + default: + return EINVAL; + } + + *c += auth_token_length; + + return ret; +} + static int pam_parse_in_data(struct sss_domain_info *domains, const char *default_domain, struct pam_data *pd, uint8_t *body, size_t blen) { - int start; - int end; - int last; + size_t start; + size_t end; + size_t last; int ret;
last = blen - 1; @@ -268,45 +314,15 @@ static int pam_parse_in_data(struct sss_domain_info *domains, if (body[end++] != '\0') return EINVAL; pd->rhost = (char *) &body[start];
- start = end; - pd->authtok_type = (int) body[start]; - - start += sizeof(uint32_t); - pd->authtok_size = (int) body[start]; - if (pd->authtok_size >= blen) return EINVAL; - - start += sizeof(uint32_t); - end = start + pd->authtok_size; - if (pd->authtok_size == 0) { - pd->authtok = NULL; - } else { - if (end <= blen) { - pd->authtok = (uint8_t *) &body[start]; - } else { - DEBUG(1, ("Invalid authtok size: %d\n", pd->authtok_size)); - return EINVAL; - } + ret = extract_authtok_v1(pd, &pd->authtok, body, blen, &end); + if (ret) { + DEBUG(1, ("Invalid auth token\n")); + return ret; } - - start = end; - pd->newauthtok_type = (int) body[start]; - - start += sizeof(uint32_t); - pd->newauthtok_size = (int) body[start]; - if (pd->newauthtok_size >= blen) return EINVAL; - - start += sizeof(uint32_t); - end = start + pd->newauthtok_size; - - if (pd->newauthtok_size == 0) { - pd->newauthtok = NULL; - } else { - if (end <= blen) { - pd->newauthtok = (uint8_t *) &body[start]; - } else { - DEBUG(1, ("Invalid newauthtok size: %d\n", pd->newauthtok_size)); - return EINVAL; - } + ret = extract_authtok_v1(pd, &pd->newauthtok, body, blen, &end); + if (ret) { + DEBUG(1, ("Invalid new auth token\n")); + return ret; }
DEBUG_PAM_DATA(4, pd); @@ -761,9 +777,9 @@ static void pam_reply(struct pam_auth_req *preq) goto done; }
- password = talloc_strndup(preq, pd->authtok, pd->authtok_size); - if (!password) { - DEBUG(0, ("Fatal: Out of memory copying password\n")); + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + if (ret) { + DEBUG(0, ("Failed to get password.\n")); goto done; }
@@ -773,10 +789,6 @@ static void pam_reply(struct pam_auth_req *preq) &exp_date, &delay_until);
pam_cache_auth_done(preq, ret, exp_date, delay_until); - if (password) { - for (i = 0; password[i]; i++) password[i] = 0; - talloc_zfree(password); - } return; } break; diff --git a/src/tests/krb5_child-test.c b/src/tests/krb5_child-test.c index b07592a46f3371166b4290305a13a16396a97dfc..e2590814bae9cda7216bac388d404c72d47518b4 100644 --- a/src/tests/krb5_child-test.c +++ b/src/tests/krb5_child-test.c @@ -167,6 +167,9 @@ create_dummy_pam_data(TALLOC_CTX *mem_ctx, const char *user, const char *password) { struct pam_data *pd; + const char *authtok; + size_t authtok_len; + errno_t ret;
pd = talloc_zero(mem_ctx, struct pam_data); if (!pd) goto fail; @@ -175,12 +178,12 @@ create_dummy_pam_data(TALLOC_CTX *mem_ctx, const char *user, pd->user = talloc_strdup(pd, user); if (!pd->user) goto fail;
- pd->authtok = discard_const(talloc_strdup(pd, password)); - if (!pd->authtok) goto fail; - pd->authtok_size = strlen(password); - pd->authtok_type = SSS_AUTHTOK_TYPE_PASSWORD; + ret = sss_authtok_set_password(pd, &pd->authtok, password, 0); + if (ret) goto fail; + + (void)sss_authtok_get_password(&pd->authtok, &authtok, &authtok_len); DEBUG(SSSDBG_FUNC_DATA, ("Authtok [%s] len [%d]\n", - pd->authtok, pd->authtok_size)); + authtok, (int)authtok_len));
return pd;
The current way we handle with auth token is manual and very error prone. The semanthics are also confusing and do not make clear how tokens are stored such that manipulating them is difficult. For example it was unclar in the code whether password tokens where 0 terminated and whether the length would incliude the null termination byte or not.
This code creates a standard structure called sss_auth_token that has a full set of getters and setters.
This patchset depends on the previous patchset I sent that fixes various tevent_req style issues.
It has been tested by performing PAM authentication requests using a kerberos based backend (IPA + AD trust), which should excercise most code paths where it is used.
Note: I wanted to make this structure completely opaque but it would have required a lot more allocations and pointers, and made the patchset larger.
Fixes: https://fedorahosted.org/sssd/ticket/1586
Simo.
Simo Sorce (4): Code can only check for cached passwords Add function to safely wipe memory. Add authtok utility functions. Change pam data auth tokens.
Makefile.am | 4 + src/db/sysdb.h | 3 +- src/db/sysdb_ops.c | 13 +-- src/providers/data_provider.h | 9 +- src/providers/dp_auth_util.c | 76 +++++--- src/providers/dp_pam_data_util.c | 113 ++++++------ src/providers/ipa/ipa_auth.c | 6 +- src/providers/krb5/krb5_auth.c | 45 +++-- src/providers/krb5/krb5_child.c | 148 ++++++++------- src/providers/krb5/krb5_child_handler.c | 59 +++++- .../krb5/krb5_delayed_online_authentication.c | 50 ++++-- src/providers/krb5/krb5_renew_tgt.c | 18 +-- src/providers/ldap/ldap_auth.c | 90 ++++------ src/providers/ldap/sdap_async.c | 4 +- src/providers/ldap/sdap_async.h | 7 +- src/providers/ldap/sdap_async_connection.c | 88 +++++---- src/providers/proxy/proxy.h | 7 +- src/providers/proxy/proxy_auth.c | 14 +- src/providers/proxy/proxy_child.c | 51 +++-- src/responder/pam/pam_LOCAL_domain.c | 52 ++---- src/responder/pam/pamsrv_cmd.c | 159 +++++++++------- src/tests/krb5_child-test.c | 13 +- src/tests/sysdb-tests.c | 6 +- src/util/authtok.c | 195 ++++++++++++++++++++ src/util/authtok.h | 180 ++++++++++++++++++ src/util/util.c | 9 + src/util/util.h | 10 + 27 files changed, 952 insertions(+), 477 deletions(-) create mode 100644 src/util/authtok.c create mode 100644 src/util/authtok.h
Make it clear to the API users that we can not take arbitrary auth tokens. We can only take a password for now so simplify and clarify the interface. --- src/db/sysdb.h | 3 +-- src/db/sysdb_ops.c | 12 +----------- src/providers/krb5/krb5_auth.c | 23 ++++++++++++++++++----- src/responder/pam/pamsrv_cmd.c | 39 ++++++++++++++++++++++++--------------- src/tests/sysdb-tests.c | 6 ++---- 5 files changed, 46 insertions(+), 37 deletions(-)
diff --git a/src/db/sysdb.h b/src/db/sysdb.h index 8fe0e81c1a98834ea70484d8ec67a4b397b9e2b9..e65bffa413998fc9564a78970a689998406ea0ef 100644 --- a/src/db/sysdb.h +++ b/src/db/sysdb.h @@ -750,8 +750,7 @@ errno_t check_failed_login_attempts(struct confdb_ctx *cdb, time_t *delayed_until); int sysdb_cache_auth(struct sysdb_ctx *sysdb, const char *name, - const uint8_t *authtok, - size_t authtok_size, + const char *password, struct confdb_ctx *cdb, bool just_check, time_t *_expire_date, diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c index 52f0cef54b9819b1f5d754dcbd56abd1d7cb0e96..9f476e98ef0c09f39659d52b927224a20e42db07 100644 --- a/src/db/sysdb_ops.c +++ b/src/db/sysdb_ops.c @@ -2654,8 +2654,7 @@ done:
int sysdb_cache_auth(struct sysdb_ctx *sysdb, const char *name, - const uint8_t *authtok, - size_t authtok_size, + const char *password, struct confdb_ctx *cdb, bool just_check, time_t *_expire_date, @@ -2670,7 +2669,6 @@ int sysdb_cache_auth(struct sysdb_ctx *sysdb, struct ldb_message *ldb_msg; const char *userhash; char *comphash; - char *password = NULL; uint64_t lastLogin = 0; int cred_expiration; uint32_t failed_login_attempts = 0; @@ -2756,13 +2754,6 @@ int sysdb_cache_auth(struct sysdb_ctx *sysdb,
/* TODO: verify user account (disabled, expired ...) */
- password = talloc_strndup(tmp_ctx, (const char *)authtok, authtok_size); - if (password == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - ret = ENOMEM; - goto done; - } - userhash = ldb_msg_find_attr_as_string(ldb_msg, SYSDB_CACHEDPWD, NULL); if (userhash == NULL || *userhash == '\0') { DEBUG(4, ("Cached credentials not available.\n")); @@ -2846,7 +2837,6 @@ done: if (_delayed_until != NULL) { *_delayed_until = delayed_until; } - if (password) for (i = 0; password[i]; i++) password[i] = 0; if (ret) { ldb_transaction_cancel(sysdb->ldb); } else { diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c index c56dfb60a5c37c6cd6c825355fcad1e49767657a..716834e34c087747b4d70a223a687b795faa5db6 100644 --- a/src/providers/krb5/krb5_auth.c +++ b/src/providers/krb5/krb5_auth.c @@ -277,16 +277,23 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, struct pam_data *pd, uid_t uid, int *pam_status, int *dp_err) { + char *password = NULL; errno_t ret;
- ret = sysdb_cache_auth(sysdb, pd->user, pd->authtok, - pd->authtok_size, cdb, true, NULL, - NULL); + password = talloc_strndup(state, pd->authtok, pd->authtok_size); + if (!password) { + DEBUG(0, ("Out of memory copying password\n")); + *pam_status = PAM_SYSTEM_ERR; + *dp_err = DP_ERR_OK; + return; + } + + ret = sysdb_cache_auth(sysdb, pd->user, password, cdb, true, NULL, NULL); if (ret != EOK) { DEBUG(1, ("Offline authentication failed\n")); *pam_status = PAM_SYSTEM_ERR; *dp_err = DP_ERR_OK; - return; + goto done; }
ret = add_user_to_delayed_online_authentication(krb5_ctx, pd, uid); @@ -296,6 +303,12 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, } *pam_status = PAM_AUTHINFO_UNAVAIL; *dp_err = DP_ERR_OFFLINE; + +done: + if (password) { + for (i = 0; password[i]; i++) password[i] = 0; + talloc_zfree(password); + } }
static errno_t krb5_auth_prepare_ccache_file(struct krb5child_req *kr, diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index 2b20544d1baf78ade232f93a2c91378ec6a7645c..8ab90e30e3f553c95a43db3ce69799b8b6d24d76 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -731,7 +731,6 @@ static void pam_reply(struct pam_auth_req *preq) struct timeval tv; struct tevent_timer *te; struct pam_data *pd; - struct sysdb_ctx *sysdb; struct pam_ctx *pctx; uint32_t user_info_type; time_t exp_date = -1; @@ -751,24 +750,34 @@ static void pam_reply(struct pam_auth_req *preq) if ((preq->domain != NULL) && (preq->domain->cache_credentials == true) && (pd->offline_auth == false)) { + const char *password = NULL;
- /* do auth with offline credentials */ - pd->offline_auth = true; + /* do auth with offline credentials */ + pd->offline_auth = true;
- sysdb = preq->domain->sysdb; - if (sysdb == NULL) { - DEBUG(0, ("Fatal: Sysdb CTX not found for " - "domain [%s]!\n", preq->domain->name)); - goto done; - } + if (preq->domain->sysdb == NULL) { + DEBUG(0, ("Fatal: Sysdb CTX not found for domain" + " [%s]!\n", preq->domain->name)); + goto done; + }
- ret = sysdb_cache_auth(sysdb, pd->user, - pd->authtok, pd->authtok_size, - pctx->rctx->cdb, false, - &exp_date, &delay_until); + password = talloc_strndup(preq, pd->authtok, pd->authtok_size); + if (!password) { + DEBUG(0, ("Fatal: Out of memory copying password\n")); + goto done; + }
- pam_cache_auth_done(preq, ret, exp_date, delay_until); - return; + ret = sysdb_cache_auth(preq->domain->sysdb, + pd->user, password, + pctx->rctx->cdb, false, + &exp_date, &delay_until); + + pam_cache_auth_done(preq, ret, exp_date, delay_until); + if (password) { + for (i = 0; password[i]; i++) password[i] = 0; + talloc_zfree(password); + } + return; } break; case SSS_PAM_CHAUTHTOK_PRELIM: diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c index 3a07a6495d3aa2d82c54acc9312704cdfd7056af..8808fbf698f9686f6814fdc4a0d690be4f4a3212 100644 --- a/src/tests/sysdb-tests.c +++ b/src/tests/sysdb-tests.c @@ -1492,8 +1492,7 @@ static void cached_authentication_without_expiration(const char *username, return; }
- ret = sysdb_cache_auth(test_ctx->sysdb, data->username, - (const uint8_t *)password, strlen(password), + ret = sysdb_cache_auth(test_ctx->sysdb, data->username, password, test_ctx->confdb, false, &expire_date, &delayed_until);
fail_unless(ret == expected_result, "sysdb_cache_auth request does not " @@ -1552,8 +1551,7 @@ static void cached_authentication_with_expiration(const char *username, data->attrs, SYSDB_MOD_REP); fail_unless(ret == EOK, "Could not modify user %s", data->username);
- ret = sysdb_cache_auth(test_ctx->sysdb, data->username, - (const uint8_t *) password, strlen(password), + ret = sysdb_cache_auth(test_ctx->sysdb, data->username, password, test_ctx->confdb, false, &expire_date, &delayed_until);
fail_unless(ret == expected_result,
This is useful for wiping passwords, as it prevents the compiler from optimizing out a memset to zero before a free() --- src/util/util.c | 9 +++++++++ src/util/util.h | 10 ++++++++++ 2 files changed, 19 insertions(+), 0 deletions(-)
diff --git a/src/util/util.c b/src/util/util.c index b812ef1b118803129caae25247efcbc1194b22f5..061291c04bb581082aa98d79b6b1ec1a1d1090ac 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -634,3 +634,12 @@ remove_ipv6_brackets(char *ipv6addr)
return EOK; } + +void safezero(void *data, size_t size) +{ + volatile uint8_t *p = data; + + while (size--) { + *p++ = 0; + } +} diff --git a/src/util/util.h b/src/util/util.h index df57a3dec4b6d42bb1e4b5e70c109317a4aff31f..c308fc2fafb35e52a5b47be05fc8eb4c9d1c069e 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -533,6 +533,16 @@ sss_escape_ip_address(TALLOC_CTX *mem_ctx, int family, const char *addr); errno_t remove_ipv6_brackets(char *ipv6addr);
+ +/** + * @brief Safely zero a segment of memory, + * prevents the compiler from optimizing out + * + * @param data The address of buffer to wipe + * @param s Size of the buffer + */ +void safezero(void *data, size_t size); + /* from sss_tc_utf8.c */ char * sss_tc_utf8_str_tolower(TALLOC_CTX *mem_ctx, const char *s);
These functions allow handling of auth tokens in a completely opaque way, with clear semantics and accessor fucntions that guarantee consistency, proper access to data and error conditions. --- Makefile.am | 2 + src/util/authtok.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/util/authtok.h | 180 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 377 insertions(+), 0 deletions(-) create mode 100644 src/util/authtok.c create mode 100644 src/util/authtok.h
diff --git a/Makefile.am b/Makefile.am index 07dcbd219bbb049df5d916b0ebc7778e63f38bc6..eb1bfe1aa38f3af17475b55ef3d082dfebd8ae4c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -368,6 +368,7 @@ dist_noinst_HEADERS = \ src/util/murmurhash3.h \ src/util/mmap_cache.h \ src/util/atomic_io.h \ + src/util/authtok.h \ src/monitor/monitor.h \ src/monitor/monitor_interfaces.h \ src/responder/common/responder.h \ @@ -506,6 +507,7 @@ libsss_util_la_SOURCES = \ src/util/sss_tc_utf8.c \ src/util/murmurhash3.c \ src/util/atomic_io.c \ + src/util/authtok.c \ src/util/sss_selinux.c \ src/util/domain_info_utils.c libsss_util_la_LIBADD = \ diff --git a/src/util/authtok.c b/src/util/authtok.c new file mode 100644 index 0000000000000000000000000000000000000000..1f45953378021e9d30559030326134794965b240 --- /dev/null +++ b/src/util/authtok.c @@ -0,0 +1,195 @@ +/* + SSSD - auth utils + + Copyright (C) Simo Sorce simo@redhat.com 2012 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses/. +*/ + +#include "authtok.h" + +enum sss_authtok_type sss_authtok_get_type(struct sss_auth_token *tok) +{ + return tok->type; +} + +size_t sss_authtok_get_size(struct sss_auth_token *tok) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_PASSWORD: + case SSS_AUTHTOK_TYPE_CCFILE: + return tok->length; + default: + return 0; + } +} + +uint8_t *sss_authtok_get_data(struct sss_auth_token *tok) +{ + return (void *)tok->data; +} + +errno_t sss_authtok_get_password(struct sss_auth_token *tok, + const char **pwd, size_t *len) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_EMPTY: + return ENOENT; + case SSS_AUTHTOK_TYPE_PASSWORD: + *pwd = (const char *)tok->data; + if (len) { + *len = tok->length - 1; + } + return EOK; + default: + return EACCES; + } +} + +errno_t sss_authtok_get_ccfile(struct sss_auth_token *tok, + const char **ccfile, size_t *len) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_EMPTY: + return ENOENT; + case SSS_AUTHTOK_TYPE_CCFILE: + *ccfile = (const char *)tok->data; + if (len) { + *len = tok->length - 1; + } + return EOK; + default: + return EACCES; + } +} + +static errno_t sss_authtok_set_string(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + enum sss_authtok_type type, + const char *context_name, + const char *str, size_t len) +{ + size_t size; + + if (len == 0) { + len = strlen(str); + } else { + while (len > 0 && str[len - 1] == '\0') len--; + } + + if (len == 0) { + /* we do not allow zero length ttyped tokens */ + return EINVAL; + } + + size = len + 1; + + tok->data = talloc_named(mem_ctx, size, context_name); + if (!tok->data) { + return ENOMEM; + } + memcpy(tok->data, str, len); + tok->data[len] = '\0'; + tok->type = type; + tok->length = size; + + return EOK; + +} + +void sss_authtok_set_empty(struct sss_auth_token *tok) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_EMPTY: + return; + case SSS_AUTHTOK_TYPE_PASSWORD: + safezero(tok->data, tok->length); + default: + break; + } + + tok->type = SSS_AUTHTOK_TYPE_EMPTY; + talloc_zfree(tok->data); + tok->length = 0; +} + +errno_t sss_authtok_set_password(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *password, size_t len) +{ + sss_authtok_set_empty(tok); + + return sss_authtok_set_string(mem_ctx, tok, + SSS_AUTHTOK_TYPE_PASSWORD, + "password", password, len); +} + +errno_t sss_authtok_set_ccfile(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *ccfile, size_t len) +{ + sss_authtok_set_empty(tok); + + return sss_authtok_set_string(mem_ctx, tok, + SSS_AUTHTOK_TYPE_CCFILE, + "ccfile", ccfile, len); +} + +errno_t sss_authtok_set(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + enum sss_authtok_type type, + uint8_t *data, size_t len) +{ + switch (type) { + case SSS_AUTHTOK_TYPE_PASSWORD: + return sss_authtok_set_password(mem_ctx, tok, (const char *)data, len); + case SSS_AUTHTOK_TYPE_CCFILE: + return sss_authtok_set_ccfile(mem_ctx, tok, (const char *)data, len); + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + return EOK; + default: + return EINVAL; + } +} + +errno_t sss_authtok_copy(TALLOC_CTX *mem_ctx, + struct sss_auth_token *src, + struct sss_auth_token *dst) +{ + sss_authtok_set_empty(dst); + + if (src->type == SSS_AUTHTOK_TYPE_EMPTY) { + return EOK; + } + + dst->data = talloc_memdup(mem_ctx, src->data, src->length); + if (!dst->data) { + return ENOMEM; + } + dst->length = src->length; + dst->type = src->type; + + return EOK; +} + +void sss_authtok_wipe_password(struct sss_auth_token *tok) +{ + if (tok->type != SSS_AUTHTOK_TYPE_PASSWORD) { + return; + } + + safezero(tok->data, tok->length); +} + diff --git a/src/util/authtok.h b/src/util/authtok.h new file mode 100644 index 0000000000000000000000000000000000000000..c750711ea373506118aab75807dc706c217f6842 --- /dev/null +++ b/src/util/authtok.h @@ -0,0 +1,180 @@ +/* + SSSD - auth utils + + Copyright (C) Simo Sorce simo@redhat.com 2012 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses/. +*/ + +#ifndef __AUTHTOK_H__ +#define __AUTHTOK_H__ + +#include "util/util.h" +#include "sss_client/sss_cli.h" + +/* Auth token structure, + * please never use directly. + * Use ss_authtok_* accesor functions instead + */ +struct sss_auth_token { + enum sss_authtok_type type; + uint8_t *data; + size_t length; +}; + +/** + * @brief Returns the token type + * + * @param tok A pointer to an sss_auth_token + * + * @return A sss_authtok_type (empty, password, ...) + */ +enum sss_authtok_type sss_authtok_get_type(struct sss_auth_token *tok); + +/** + * @brief Returns the token size + * + * @param tok A pointer to an sss_auth_token + * + * @return The current size of the token payload + */ +size_t sss_authtok_get_size(struct sss_auth_token *tok); + +/** + * @brief Get the data buffer + * + * @param tok A pointer to an sss_auth_token + * + * @return A pointer to the token payload + */ +uint8_t *sss_authtok_get_data(struct sss_auth_token *tok); + +/** + * @brief Returns a const string if the auth token is of type + SSS_AUTHTOK_TYPE_PASSWORD, otherwise it returns an error + * + * @param tok A pointer to an sss_auth_token + * @param pwd A pointer to a const char *, that will point to a null + * terminated string + * @param len The length of the password string + * + * @return EOK on success + * ENOENT if the token is empty + * EACCESS if the token is not a password token + */ +errno_t sss_authtok_get_password(struct sss_auth_token *tok, + const char **pwd, size_t *len); + +/** + * @brief Set a password into a an auth token, replacing any previous data + * + * @param mem_ctx A memory context use to allocate the internal data + * @param tok A pointer to a sss_auth_token structure to change + * @param password A string + * @param len The length of the string or, if 0 is passed, + * then strlen(password) will be used internally. + * + * @return EOK on success + * ENOMEM on error + */ +errno_t sss_authtok_set_password(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *password, size_t len); + +/** + * @brief Returns a const string if the auth token is of type + SSS_AUTHTOK_TYPE_CCFILE, otherwise it returns an error + * + * @param tok A pointer to an sss_auth_token + * @param ccfile A pointer to a const char *, that will point to a null + * terminated string + * @param len The length of the string + * + * @return EOK on success + * ENOENT if the token is empty + * EACCESS if the token is not a password token + */ +errno_t sss_authtok_get_ccfile(struct sss_auth_token *tok, + const char **ccfile, size_t *len); + +/** + * @brief Set a cc file name into a an auth token, replacing any previous data + * + * @param mem_ctx A memory context use to allocate the internal data + * @param tok A pointer to a sss_auth_token structure to change + * @param ccfile A null terminated string + * @param len The length of the string + * + * @return EOK on success + * ENOMEM on error + */ +errno_t sss_authtok_set_ccfile(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *ccfile, size_t len); + +/** + * @brief Resets an auth token to the empty status + * + * @param tok A pointer to a sss_auth_token structure to reset + * + * NOTE: This function uses safezero() on the payload if the type + * is SSS_AUTHTOK_TYPE_PASSWORD + */ +void sss_authtok_set_empty(struct sss_auth_token *tok); + +/** + * @brief Set an auth token by type, replacing any previous data + * + * @param mem_ctx A memory context use to allocate the internal data + * @param tok A pointer to a sss_auth_token structure to change + * @param type A valid authtok type + * @param ccfile A data pointer + * @param len The length of the data + * + * @return EOK on success + * ENOMEM or EINVAL on error + */ +errno_t sss_authtok_set(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + enum sss_authtok_type type, + uint8_t *data, size_t len); + +/** + * @brief Copy an auth token from source to destination + * + * @param mem_ctx The memory context to use for allocations on dst + * @param src The source auth token + * @param dst The destination auth token + * + * @return EOK on success + * ENOMEM on error + */ +errno_t sss_authtok_copy(TALLOC_CTX *mem_ctx, + struct sss_auth_token *src, + struct sss_auth_token *dst); + +/** + * @brief Uses safezero to wipe the password from memory if the + * authtoken contains a password, otherwise does nothing. + * + * @param tok A pointer to a sss_auth_token structure to change + * + * NOTE: This function should only be used in destructors or similar + * functions where freing the actual string is unsafe and where it can + * be guaranteed that the auth token will not be used anymore. + * Use sss_authtok_set_empty() in normal circumstances. + */ +void sss_authtok_wipe_password(struct sss_auth_token *tok); + +#endif /* __AUTHTOK_H__ */
Use the new authtok abstraction and interfaces throught the code. --- Makefile.am | 2 + src/db/sysdb_ops.c | 1 - src/providers/data_provider.h | 9 +- src/providers/dp_auth_util.c | 76 +++++++---- src/providers/dp_pam_data_util.c | 113 ++++++++------- src/providers/ipa/ipa_auth.c | 6 +- src/providers/krb5/krb5_auth.c | 48 +++---- src/providers/krb5/krb5_child.c | 148 ++++++++++---------- src/providers/krb5/krb5_child_handler.c | 59 +++++++-- .../krb5/krb5_delayed_online_authentication.c | 50 +++++--- src/providers/krb5/krb5_renew_tgt.c | 18 +-- src/providers/ldap/ldap_auth.c | 90 +++++------- src/providers/ldap/sdap_async.c | 4 +- src/providers/ldap/sdap_async.h | 7 +- src/providers/ldap/sdap_async_connection.c | 88 +++++++----- src/providers/proxy/proxy.h | 7 +- src/providers/proxy/proxy_auth.c | 14 +- src/providers/proxy/proxy_child.c | 51 ++++--- src/responder/pam/pam_LOCAL_domain.c | 52 +++----- src/responder/pam/pamsrv_cmd.c | 134 ++++++++++-------- src/tests/krb5_child-test.c | 13 +- 21 files changed, 530 insertions(+), 460 deletions(-)
diff --git a/Makefile.am b/Makefile.am index eb1bfe1aa38f3af17475b55ef3d082dfebd8ae4c..e7d2626988203400017d6719475825af03e062a3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1444,6 +1444,7 @@ krb5_child_SOURCES = \ src/util/user_info_msg.c \ src/util/sss_krb5.c \ src/util/atomic_io.c \ + src/util/authtok.c \ src/util/util.c \ src/util/signal.c \ src/sss_client/common.c @@ -1465,6 +1466,7 @@ ldap_child_SOURCES = \ src/providers/ldap/ldap_child.c \ src/util/sss_krb5.c \ src/util/atomic_io.c \ + src/util/authtok.c \ src/util/util.c \ src/util/signal.c ldap_child_CFLAGS = \ diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c index 9f476e98ef0c09f39659d52b927224a20e42db07..8349115ce9e34a894b8f115807bc666a25447b8c 100644 --- a/src/db/sysdb_ops.c +++ b/src/db/sysdb_ops.c @@ -2677,7 +2677,6 @@ int sysdb_cache_auth(struct sysdb_ctx *sysdb, time_t expire_date = -1; time_t delayed_until = -1; int ret; - int i;
if (name == NULL || *name == '\0') { DEBUG(1, ("Missing user name.\n")); diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h index bb944509da9f1dc89216266cf62c57fb4127fd57..b370aa51dbe4015a26512a0f003defdb6851bf63 100644 --- a/src/providers/data_provider.h +++ b/src/providers/data_provider.h @@ -41,6 +41,7 @@ #include "sbus/sssd_dbus.h" #include "sbus/sbus_client.h" #include "sss_client/sss_cli.h" +#include "util/authtok.h"
#define DATA_PROVIDER_VERSION 0x0001 #define DATA_PROVIDER_PIPE "private/sbus-dp" @@ -162,18 +163,14 @@ struct response_data {
struct pam_data { int cmd; - uint32_t authtok_type; - uint32_t authtok_size; - uint32_t newauthtok_type; - uint32_t newauthtok_size; char *domain; char *user; char *service; char *tty; char *ruser; char *rhost; - uint8_t *authtok; - uint8_t *newauthtok; + struct sss_auth_token authtok; + struct sss_auth_token newauthtok; uint32_t cli_pid;
int pam_status; diff --git a/src/providers/dp_auth_util.c b/src/providers/dp_auth_util.c index 9a67564b78e558642f4116528d210251a0d9b5fd..54f0ee8ed6f1d537410a91f93e55316fc9b89886 100644 --- a/src/providers/dp_auth_util.c +++ b/src/providers/dp_auth_util.c @@ -24,30 +24,43 @@ bool dp_pack_pam_request(DBusMessage *msg, struct pam_data *pd) { dbus_bool_t db_ret; + const char *service; + const char *tty; + const char *ruser; + const char *rhost; + uint32_t authtok_type; + uint32_t authtok_length; + uint8_t *authtok_data; + uint32_t new_authtok_type; + uint32_t new_authtok_length; + uint8_t *new_authtok_data;
if (pd->user == NULL) return false; - if (pd->service == NULL) pd->service = talloc_strdup(pd, ""); - if (pd->tty == NULL) pd->tty = talloc_strdup(pd, ""); - if (pd->ruser == NULL) pd->ruser = talloc_strdup(pd, ""); - if (pd->rhost == NULL) pd->rhost = talloc_strdup(pd, ""); - + service = pd->service ? pd->service : ""; + tty = pd->tty ? pd->tty : ""; + ruser = pd->ruser ? pd->ruser : ""; + rhost = pd->rhost ? pd->rhost : ""; + authtok_type = (uint32_t)sss_authtok_get_type(&pd->authtok); + authtok_data = sss_authtok_get_data(&pd->authtok); + authtok_length = sss_authtok_get_size(&pd->authtok); + new_authtok_type = (uint32_t)sss_authtok_get_type(&pd->newauthtok); + new_authtok_data = sss_authtok_get_data(&pd->newauthtok); + new_authtok_length = sss_authtok_get_size(&pd->newauthtok);
db_ret = dbus_message_append_args(msg, DBUS_TYPE_INT32, &(pd->cmd), DBUS_TYPE_STRING, &(pd->user), DBUS_TYPE_STRING, &(pd->domain), - DBUS_TYPE_STRING, &(pd->service), - DBUS_TYPE_STRING, &(pd->tty), - DBUS_TYPE_STRING, &(pd->ruser), - DBUS_TYPE_STRING, &(pd->rhost), - DBUS_TYPE_UINT32, &(pd->authtok_type), + DBUS_TYPE_STRING, &service, + DBUS_TYPE_STRING, &tty, + DBUS_TYPE_STRING, &ruser, + DBUS_TYPE_STRING, &rhost, + DBUS_TYPE_UINT32, &authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd->authtok), - (pd->authtok_size), - DBUS_TYPE_UINT32, &(pd->newauthtok_type), + &authtok_data, authtok_length, + DBUS_TYPE_UINT32, &new_authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd->newauthtok), - pd->newauthtok_size, + &new_authtok_data, new_authtok_length, DBUS_TYPE_INT32, &(pd->priv), DBUS_TYPE_UINT32, &(pd->cli_pid), DBUS_TYPE_INVALID); @@ -61,6 +74,12 @@ bool dp_unpack_pam_request(DBusMessage *msg, TALLOC_CTX *mem_ctx, dbus_bool_t db_ret; int ret; struct pam_data pd; + uint32_t authtok_type; + uint32_t authtok_length; + uint8_t *authtok_data; + uint32_t new_authtok_type; + uint32_t new_authtok_length; + uint8_t *new_authtok_data;
memset(&pd, 0, sizeof(pd));
@@ -72,14 +91,12 @@ bool dp_unpack_pam_request(DBusMessage *msg, TALLOC_CTX *mem_ctx, DBUS_TYPE_STRING, &(pd.tty), DBUS_TYPE_STRING, &(pd.ruser), DBUS_TYPE_STRING, &(pd.rhost), - DBUS_TYPE_UINT32, &(pd.authtok_type), + DBUS_TYPE_UINT32, &authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd.authtok), - &(pd.authtok_size), - DBUS_TYPE_UINT32, &(pd.newauthtok_type), + &authtok_data, &authtok_length, + DBUS_TYPE_UINT32, &new_authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd.newauthtok), - &(pd.newauthtok_size), + &new_authtok_data, &new_authtok_length, DBUS_TYPE_INT32, &(pd.priv), DBUS_TYPE_UINT32, &(pd.cli_pid), DBUS_TYPE_INVALID); @@ -95,14 +112,17 @@ bool dp_unpack_pam_request(DBusMessage *msg, TALLOC_CTX *mem_ctx, return false; }
- if (pd.authtok_size != 0 && pd.authtok != NULL) { - memset(pd.authtok, 0, pd.authtok_size); - pd.authtok_size = 0; + ret = sss_authtok_set(*new_pd, &((*new_pd)->authtok), authtok_type, + authtok_data, authtok_length); + if (ret) { + DEBUG(1, ("Failed to set auth token: %d [%s]\n", ret, strerror(ret))); + return false; } - - if (pd.newauthtok_size != 0 && pd.newauthtok != NULL) { - memset(pd.newauthtok, 0, pd.newauthtok_size); - pd.newauthtok_size = 0; + ret = sss_authtok_set(*new_pd, &((*new_pd)->newauthtok), new_authtok_type, + new_authtok_data, new_authtok_length); + if (ret) { + DEBUG(1, ("Failed to set auth token: %d [%s]\n", ret, strerror(ret))); + return false; }
return true; diff --git a/src/providers/dp_pam_data_util.c b/src/providers/dp_pam_data_util.c index 889c47f00bfb49effab982ed40454b5120b84bf6..64f0d69bd0e8ebc28df958c393b40afcb5e18c31 100644 --- a/src/providers/dp_pam_data_util.c +++ b/src/providers/dp_pam_data_util.c @@ -25,26 +25,6 @@ #include "providers/data_provider.h"
-#define PD_STR_COPY(el) do { \ - if (old_pd->el != NULL) { \ - pd->el = talloc_strdup(pd, old_pd->el); \ - if (pd->el == NULL) { \ - DEBUG(1, ("talloc_strdup failed.\n")); \ - goto failed; \ - } \ - } \ -} while(0) - -#define PD_MEM_COPY(el, size) do { \ - if (old_pd->el != NULL) { \ - pd->el = talloc_memdup(pd, old_pd->el, (size)); \ - if (pd->el == NULL) { \ - DEBUG(1, ("talloc_memdup failed.\n")); \ - goto failed; \ - } \ - } \ -} while(0) - #define PAM_SAFE_ITEM(item) item ? item : "not set"
static const char *pamcmd2str(int cmd) { @@ -72,17 +52,11 @@ int pam_data_destructor(void *ptr) { struct pam_data *pd = talloc_get_type(ptr, struct pam_data);
- if (pd->authtok_size != 0 && pd->authtok != NULL) { - memset(pd->authtok, 0, pd->authtok_size); - pd->authtok_size = 0; - } + /* make sure to wipe any password from memory before freeing */ + sss_authtok_wipe_password(&pd->authtok); + sss_authtok_wipe_password(&pd->newauthtok);
- if (pd->newauthtok_size != 0 && pd->newauthtok != NULL) { - memset(pd->newauthtok, 0, pd->newauthtok_size); - pd->newauthtok_size = 0; - } - - return EOK; + return 0; }
struct pam_data *create_pam_data(TALLOC_CTX *mem_ctx) @@ -100,41 +74,72 @@ struct pam_data *create_pam_data(TALLOC_CTX *mem_ctx) return pd; }
-errno_t copy_pam_data(TALLOC_CTX *mem_ctx, struct pam_data *old_pd, - struct pam_data **new_pd) +errno_t copy_pam_data(TALLOC_CTX *mem_ctx, struct pam_data *src, + struct pam_data **dst) { struct pam_data *pd = NULL; + errno_t ret;
pd = create_pam_data(mem_ctx); if (pd == NULL) { - DEBUG(1, ("create_pam_data failed.\n")); - return ENOMEM; + ret = ENOMEM; + goto failed; }
- pd->cmd = old_pd->cmd; - pd->authtok_type = old_pd->authtok_type; - pd->authtok_size = old_pd->authtok_size; - pd->newauthtok_type = old_pd->newauthtok_type; - pd->newauthtok_size = old_pd->newauthtok_size; - pd->priv = old_pd->priv; + pd->cmd = src->cmd; + pd->priv = src->priv;
- PD_STR_COPY(domain); - PD_STR_COPY(user); - PD_STR_COPY(service); - PD_STR_COPY(tty); - PD_STR_COPY(ruser); - PD_STR_COPY(rhost); - PD_MEM_COPY(authtok, old_pd->authtok_size); - PD_MEM_COPY(newauthtok, old_pd->newauthtok_size); - pd->cli_pid = old_pd->cli_pid; + pd->domain = talloc_strdup(pd, src->domain); + if (pd->domain == NULL && src->domain != NULL) { + ret = ENOMEM; + goto failed; + } + pd->user = talloc_strdup(pd, src->user); + if (pd->user == NULL && src->user != NULL) { + ret = ENOMEM; + goto failed; + } + pd->service = talloc_strdup(pd, src->service); + if (pd->service == NULL && src->service != NULL) { + ret = ENOMEM; + goto failed; + } + pd->tty = talloc_strdup(pd, src->tty); + if (pd->tty == NULL && src->tty != NULL) { + ret = ENOMEM; + goto failed; + } + pd->ruser = talloc_strdup(pd, src->ruser); + if (pd->ruser == NULL && src->ruser != NULL) { + ret = ENOMEM; + goto failed; + } + pd->rhost = talloc_strdup(pd, src->rhost); + if (pd->rhost == NULL && src->rhost != NULL) { + ret = ENOMEM; + goto failed; + } + + pd->cli_pid = src->cli_pid; + + ret = sss_authtok_copy(pd, &src->authtok, &pd->authtok); + if (ret) { + goto failed; + } + + ret = sss_authtok_copy(pd, &src->newauthtok, &pd->newauthtok); + if (ret) { + goto failed; + }
- *new_pd = pd; + *dst = pd;
return EOK;
failed: talloc_free(pd); - return ENOMEM; + DEBUG(1, ("copy_pam_data failed: (%d) %s.\n", ret, strerror(ret))); + return ret; }
void pam_print_data(int l, struct pam_data *pd) @@ -146,10 +151,8 @@ void pam_print_data(int l, struct pam_data *pd) DEBUG(l, ("tty: %s\n", PAM_SAFE_ITEM(pd->tty))); DEBUG(l, ("ruser: %s\n", PAM_SAFE_ITEM(pd->ruser))); DEBUG(l, ("rhost: %s\n", PAM_SAFE_ITEM(pd->rhost))); - DEBUG(l, ("authtok type: %d\n", pd->authtok_type)); - DEBUG(l, ("authtok size: %d\n", pd->authtok_size)); - DEBUG(l, ("newauthtok type: %d\n", pd->newauthtok_type)); - DEBUG(l, ("newauthtok size: %d\n", pd->newauthtok_size)); + DEBUG(l, ("authtok type: %d\n", sss_authtok_get_type(&pd->authtok))); + DEBUG(l, ("newauthtok type: %d\n", sss_authtok_get_type(&pd->newauthtok))); DEBUG(l, ("priv: %d\n", pd->priv)); DEBUG(l, ("cli_pid: %d\n", pd->cli_pid)); } diff --git a/src/providers/ipa/ipa_auth.c b/src/providers/ipa/ipa_auth.c index eb62f0295cc0dc36daad9d4147556d993c7f1509..ee15afa5c83c0c68d19e169649ae6958a1553bd1 100644 --- a/src/providers/ipa/ipa_auth.c +++ b/src/providers/ipa/ipa_auth.c @@ -332,7 +332,6 @@ static void ipa_migration_flag_connect_done(struct tevent_req *req) const char **attrs; struct ldb_message *user_msg; const char *dn; - struct dp_opt_blob password; int dp_err = DP_ERR_FATAL; int ret;
@@ -374,11 +373,8 @@ static void ipa_migration_flag_connect_done(struct tevent_req *req) goto done; }
- password.data = state->pd->authtok; - password.length = state->pd->authtok_size; - req = sdap_auth_send(state, state->ev, state->sh, NULL, NULL, dn, - "password", password); + &state->pd->authtok); if (req == NULL) { DEBUG(SSSDBG_OP_FAILURE, ("sdap_auth_send failed.\n")); goto done; diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c index 716834e34c087747b4d70a223a687b795faa5db6..48fbf0e4f0ccb45c620ae731ebf39aeef3c130cf 100644 --- a/src/providers/krb5/krb5_auth.c +++ b/src/providers/krb5/krb5_auth.c @@ -277,12 +277,12 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, struct pam_data *pd, uid_t uid, int *pam_status, int *dp_err) { - char *password = NULL; + const char *password = NULL; errno_t ret;
- password = talloc_strndup(state, pd->authtok, pd->authtok_size); - if (!password) { - DEBUG(0, ("Out of memory copying password\n")); + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + if (ret != EOK) { + DEBUG(0, ("Failed to get password [%d] %s\n", ret, strerror(ret))); *pam_status = PAM_SYSTEM_ERR; *dp_err = DP_ERR_OK; return; @@ -293,7 +293,7 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, DEBUG(1, ("Offline authentication failed\n")); *pam_status = PAM_SYSTEM_ERR; *dp_err = DP_ERR_OK; - goto done; + return; }
ret = add_user_to_delayed_online_authentication(krb5_ctx, pd, uid); @@ -303,12 +303,6 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, } *pam_status = PAM_AUTHINFO_UNAVAIL; *dp_err = DP_ERR_OFFLINE; - -done: - if (password) { - for (i = 0; password[i]; i++) password[i] = 0; - talloc_zfree(password); - } }
static errno_t krb5_auth_prepare_ccache_file(struct krb5child_req *kr, @@ -454,9 +448,17 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx, case SSS_PAM_AUTHENTICATE: case SSS_CMD_RENEW: case SSS_PAM_CHAUTHTOK: + if (sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { + DEBUG(1, ("Missing authtok for user [%s].\n", pd->user)); + state->pam_status = PAM_SYSTEM_ERR; + state->dp_err = DP_ERR_FATAL; + ret = EINVAL; + goto done; + } break; case SSS_PAM_CHAUTHTOK_PRELIM: - if (pd->priv == 1 && pd->authtok_size == 0) { + if (pd->priv == 1 && + sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { DEBUG(4, ("Password reset by root is not supported.\n")); state->pam_status = PAM_PERM_DENIED; state->dp_err = DP_ERR_OK; @@ -778,7 +780,7 @@ static void krb5_auth_done(struct tevent_req *subreq) struct krb5_child_response *res; const char *store_ccname; struct fo_server *search_srv; - char *password = NULL; + const char *password = NULL;
ret = handle_child_recv(subreq, pd, &buf, &len); talloc_zfree(subreq); @@ -1058,23 +1060,21 @@ static void krb5_auth_done(struct tevent_req *subreq) break; case SSS_PAM_AUTHENTICATE: case SSS_PAM_CHAUTHTOK_PRELIM: - password = talloc_size(state, pd->authtok_size + 1); - if (password != NULL) { - memcpy(password, pd->authtok, pd->authtok_size); - password[pd->authtok_size] = '\0'; - } + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); break; case SSS_PAM_CHAUTHTOK: - password = talloc_size(state, pd->newauthtok_size + 1); - if (password != NULL) { - memcpy(password, pd->newauthtok, pd->newauthtok_size); - password[pd->newauthtok_size] = '\0'; - } + ret = sss_authtok_get_password(&pd->newauthtok, + &password, NULL); break; default: DEBUG(0, ("unsupported PAM command [%d].\n", pd->cmd)); }
+ if (ret != EOK) { + DEBUG(0, ("Failed to get password [%d] %s\n", ret, strerror(ret))); + /* password caching failures are not fatal errors */ + } + if (password == NULL) { if (pd->cmd != SSS_CMD_RENEW) { DEBUG(0, ("password not available, offline auth may not work.\n")); @@ -1084,8 +1084,6 @@ static void krb5_auth_done(struct tevent_req *subreq) goto done; }
- talloc_set_destructor((TALLOC_CTX *)password, password_destructor); - ret = sysdb_cache_password(state->sysdb, pd->user, password); if (ret) { DEBUG(2, ("Failed to cache password, offline auth may not work." diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c index e7776248b8f6284f86f8fc11b00cd4b122af13df..af35d5e5d301fbca18e100ea5f29eb2aa1fc0850 100644 --- a/src/providers/krb5/krb5_child.c +++ b/src/providers/krb5/krb5_child.c @@ -1014,7 +1014,7 @@ done: }
static krb5_error_code get_and_save_tgt(struct krb5_req *kr, - char *password) + const char *password) { krb5_error_code kerr = 0; int ret; @@ -1035,7 +1035,8 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr, DEBUG(SSSDBG_TRACE_FUNC, ("Attempting kinit for realm [%s]\n",realm_name)); kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - password, sss_krb5_prompter, kr, 0, + discard_const(password), + sss_krb5_prompter, kr, 0, NULL, kr->options); if (kerr != 0) { KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); @@ -1130,8 +1131,8 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) { int ret; krb5_error_code kerr = 0; - char *pass_str = NULL; - char *newpass_str = NULL; + const char *password = NULL; + const char *newpassword = NULL; int pam_status = PAM_SYSTEM_ERR; int result_code = -1; krb5_data result_code_string; @@ -1146,20 +1147,15 @@ static errno_t changepw_child(int fd, struct krb5_req *kr)
DEBUG(SSSDBG_TRACE_LIBS, ("Password change operation\n"));
- if (kr->pd->authtok_type != SSS_AUTHTOK_TYPE_PASSWORD) { + ret = sss_authtok_get_password(&kr->pd->authtok, &password, NULL); + if (ret != EOK) { + DEBUG(1, ("Failed to fetch current password [%d] %s.\n", + ret, strerror(ret))); pam_status = PAM_CRED_INSUFFICIENT; kerr = KRB5KRB_ERR_GENERIC; goto sendresponse; }
- pass_str = talloc_strndup(kr, (const char *) kr->pd->authtok, - kr->pd->authtok_size); - if (pass_str == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - kerr = KRB5KRB_ERR_GENERIC; - goto sendresponse; - } - changepw_princ = talloc_asprintf(kr, "%s@%s", SSSD_KRB5_CHANGEPW_PRINCIPAL, kr->krb5_ctx->realm); if (changepw_princ == NULL) { @@ -1180,7 +1176,8 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) DEBUG(SSSDBG_TRACE_FUNC, ("Attempting kinit for realm [%s]\n",realm_name)); kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - pass_str, prompter, kr, 0, + discard_const(password), + prompter, kr, 0, changepw_princ, kr->options); if (kerr != 0) { @@ -1188,9 +1185,7 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) goto sendresponse; }
- memset(pass_str, 0, kr->pd->authtok_size); - talloc_zfree(pass_str); - memset(kr->pd->authtok, 0, kr->pd->authtok_size); + sss_authtok_set_empty(&kr->pd->authtok);
if (kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) { DEBUG(SSSDBG_TRACE_LIBS, @@ -1201,17 +1196,18 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) goto sendresponse; }
- newpass_str = talloc_strndup(kr, (const char *) kr->pd->newauthtok, - kr->pd->newauthtok_size); - if (newpass_str == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); + ret = sss_authtok_get_password(&kr->pd->newauthtok, &newpassword, NULL); + if (ret != EOK) { + DEBUG(1, ("Failed to fetch new password [%d] %s.\n", + ret, strerror(ret))); kerr = KRB5KRB_ERR_GENERIC; goto sendresponse; }
memset(&result_code_string, 0, sizeof(krb5_data)); memset(&result_string, 0, sizeof(krb5_data)); - kerr = krb5_change_password(kr->ctx, kr->creds, newpass_str, &result_code, + kerr = krb5_change_password(kr->ctx, kr->creds, + discard_const(newpassword), &result_code, &result_code_string, &result_string);
if (kerr == KRB5_KDC_UNREACH) { @@ -1267,10 +1263,9 @@ static errno_t changepw_child(int fd, struct krb5_req *kr)
krb5_free_cred_contents(kr->ctx, kr->creds);
- kerr = get_and_save_tgt(kr, newpass_str); - memset(newpass_str, 0, kr->pd->newauthtok_size); - talloc_zfree(newpass_str); - memset(kr->pd->newauthtok, 0, kr->pd->newauthtok_size); + kerr = get_and_save_tgt(kr, newpassword); + + sss_authtok_set_empty(&kr->pd->newauthtok);
pam_status = kerr_to_status(kerr);
@@ -1287,27 +1282,20 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) { int ret; krb5_error_code kerr = 0; - char *pass_str = NULL; + const char *password = NULL; char *changepw_princ = NULL; int pam_status = PAM_SYSTEM_ERR;
DEBUG(SSSDBG_TRACE_LIBS, ("Attempting to get a TGT\n"));
- if (kr->pd->authtok_type != SSS_AUTHTOK_TYPE_PASSWORD) { + ret = sss_authtok_get_password(&kr->pd->authtok, &password, NULL); + if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Unknown authtok type\n")); pam_status = PAM_CRED_INSUFFICIENT; kerr = KRB5KRB_ERR_GENERIC; goto sendresponse; }
- pass_str = talloc_strndup(kr, (const char *) kr->pd->authtok, - kr->pd->authtok_size); - if (pass_str == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - kerr = KRB5KRB_ERR_GENERIC; - goto sendresponse; - } - changepw_princ = talloc_asprintf(kr, "%s@%s", SSSD_KRB5_CHANGEPW_PRINCIPAL, kr->krb5_ctx->realm); if (changepw_princ == NULL) { @@ -1318,7 +1306,7 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) DEBUG(SSSDBG_FUNC_DATA, ("Created a changepw principal [%s]\n", changepw_princ));
- kerr = get_and_save_tgt(kr, pass_str); + kerr = get_and_save_tgt(kr, password);
/* If the password is expired the KDC will always return KRB5KDC_ERR_KEY_EXP regardless if the supplied password is correct or @@ -1334,7 +1322,8 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) DEBUG(1, ("Failed to unset expire callback, continue ...\n")); } kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - pass_str, sss_krb5_prompter, kr, 0, + discard_const(password), + sss_krb5_prompter, kr, 0, changepw_princ, kr->options); krb5_free_cred_contents(kr->ctx, kr->creds); @@ -1343,9 +1332,7 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) } }
- memset(pass_str, 0, kr->pd->authtok_size); - talloc_zfree(pass_str); - memset(kr->pd->authtok, 0, kr->pd->authtok_size); + sss_authtok_set_empty(&kr->pd->authtok);
pam_status = kerr_to_status(kerr);
@@ -1400,25 +1387,20 @@ static errno_t renew_tgt_child(int fd, struct krb5_req *kr) int ret; int status = PAM_AUTHTOK_ERR; int kerr; - char *ccname; + const char *ccname; krb5_ccache ccache = NULL;
DEBUG(SSSDBG_TRACE_LIBS, ("Renewing a ticket\n"));
- if (kr->pd->authtok_type != SSS_AUTHTOK_TYPE_CCFILE) { - DEBUG(1, ("Unsupported authtok type for TGT renewal [%d].\n", - kr->pd->authtok_type)); + ret = sss_authtok_get_ccfile(&kr->pd->authtok, &ccname, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + ("Unsupported authtok type for TGT renewal [%d].\n", + sss_authtok_get_type(&kr->pd->authtok))); kerr = EINVAL; goto done; }
- ccname = talloc_strndup(kr, (char *) kr->pd->authtok, kr->pd->authtok_size); - if (ccname == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - kerr = ENOMEM; - goto done; - } - kerr = krb5_cc_resolve(kr->ctx, ccname, &ccache); if (kerr != 0) { KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); @@ -1511,6 +1493,38 @@ static errno_t create_empty_ccache(int fd, struct krb5_req *kr) return ret; }
+static errno_t unpack_authtok(TALLOC_CTX *mem_ctx, struct sss_auth_token *tok, + uint8_t *buf, size_t size, size_t *p) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + errno_t ret = EOK; + + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, buf + *p, size, p); + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_length, buf + *p, size, p); + if ((*p + auth_token_length) > size) { + return EINVAL; + } + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_set_password(mem_ctx, tok, (char *)(buf + *p), 0); + break; + case SSS_AUTHTOK_TYPE_CCFILE: + ret = sss_authtok_set_ccfile(mem_ctx, tok, (char *)(buf + *p), 0); + break; + default: + return EINVAL; + } + + if (ret == EOK) { + *p += auth_token_length; + } + return ret; +} + static errno_t unpack_buffer(uint8_t *buf, size_t size, struct pam_data *pd, struct krb5_req *kr, uint32_t *offline) { @@ -1518,6 +1532,7 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size, struct pam_data *pd, uint32_t len; uint32_t validate; uint32_t different_realm; + errno_t ret;
DEBUG(SSSDBG_TRACE_LIBS, ("total buffer size: [%d]\n", size));
@@ -1558,35 +1573,26 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size, struct pam_data *pd, if (kr->keytab == NULL) return ENOMEM; p += len;
- SAFEALIGN_COPY_UINT32_CHECK(&pd->authtok_type, buf + p, size, &p); - SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p); - if ((p + len) > size) return EINVAL; - pd->authtok = (uint8_t *)talloc_strndup(pd, (char *)(buf + p), len); - if (pd->authtok == NULL) return ENOMEM; - pd->authtok_size = len + 1; - p += len; + ret = unpack_authtok(pd, &pd->authtok, buf, size, &p); + if (ret) { + return ret; + }
DEBUG(SSSDBG_CONF_SETTINGS, ("ccname: [%s] keytab: [%s]\n", kr->ccname, kr->keytab)); } else { kr->ccname = NULL; kr->keytab = NULL; - pd->authtok = NULL; - pd->authtok_size = 0; + sss_authtok_set_empty(&pd->authtok); }
if (pd->cmd == SSS_PAM_CHAUTHTOK) { - SAFEALIGN_COPY_UINT32_CHECK(&pd->newauthtok_type, buf + p, size, &p); - SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p); - - if ((p + len) > size) return EINVAL; - pd->newauthtok = (uint8_t *)talloc_strndup(pd, (char *)(buf + p), len); - if (pd->newauthtok == NULL) return ENOMEM; - pd->newauthtok_size = len + 1; - p += len; + ret = unpack_authtok(pd, &pd->newauthtok, buf, size, &p); + if (ret) { + return ret; + } } else { - pd->newauthtok = NULL; - pd->newauthtok_size = 0; + sss_authtok_set_empty(&pd->newauthtok); }
if (pd->cmd == SSS_PAM_ACCT_MGMT) { diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c index e792db3f7a6ebe7857b1ec699bc37d52ae3cad5d..5adbcf700ebf02a2aa524af3cecab51e543b4986 100644 --- a/src/providers/krb5/krb5_child_handler.c +++ b/src/providers/krb5/krb5_child_handler.c @@ -85,6 +85,43 @@ static int child_io_destructor(void *ptr) return EOK; }
+static errno_t pack_authtok(struct io_buffer *buf, size_t *rp, + struct sss_auth_token *tok) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + const char *data; + size_t len; + errno_t ret = EOK; + + auth_token_type = sss_authtok_get_type(tok); + + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + auth_token_length = 0; + data = ""; + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_get_password(tok, &data, &len); + auth_token_length = len + 1; + break; + case SSS_AUTHTOK_TYPE_CCFILE: + ret = sss_authtok_get_password(tok, &data, &len); + auth_token_length = len + 1; + break; + default: + ret = EINVAL; + } + + if (ret == EOK) { + SAFEALIGN_COPY_UINT32(&buf->data[*rp], &auth_token_type, rp); + SAFEALIGN_COPY_UINT32(&buf->data[*rp], &auth_token_length, rp); + safealign_memcpy(&buf->data[*rp], data, auth_token_length, rp); + } + + return ret; +} + static errno_t create_send_buffer(struct krb5child_req *kr, struct io_buffer **io_buf) { @@ -94,6 +131,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr, uint32_t validate; uint32_t different_realm; size_t username_len = 0; + errno_t ret;
keytab = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_KEYTAB); if (keytab == NULL) { @@ -117,11 +155,12 @@ static errno_t create_send_buffer(struct krb5child_req *kr, kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM || kr->pd->cmd == SSS_PAM_CHAUTHTOK) { buf->size += 4*sizeof(uint32_t) + strlen(kr->ccname) + strlen(keytab) + - kr->pd->authtok_size; + sss_authtok_get_size(&kr->pd->authtok); }
if (kr->pd->cmd == SSS_PAM_CHAUTHTOK) { - buf->size += 2*sizeof(uint32_t) + kr->pd->newauthtok_size; + buf->size += 2*sizeof(uint32_t) + + sss_authtok_get_size(&kr->pd->newauthtok); }
if (kr->pd->cmd == SSS_PAM_ACCT_MGMT) { @@ -157,17 +196,17 @@ static errno_t create_send_buffer(struct krb5child_req *kr, SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(keytab), &rp); safealign_memcpy(&buf->data[rp], keytab, strlen(keytab), &rp);
- SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->authtok_type, &rp); - SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->authtok_size, &rp); - safealign_memcpy(&buf->data[rp], kr->pd->authtok, - kr->pd->authtok_size, &rp); + ret = pack_authtok(buf, &rp, &kr->pd->authtok); + if (ret) { + return ret; + } }
if (kr->pd->cmd == SSS_PAM_CHAUTHTOK) { - SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->newauthtok_type, &rp); - SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->newauthtok_size, &rp); - safealign_memcpy(&buf->data[rp], kr->pd->newauthtok, - kr->pd->newauthtok_size, &rp); + ret = pack_authtok(buf, &rp, &kr->pd->newauthtok); + if (ret) { + return ret; + } }
if (kr->pd->cmd == SSS_PAM_ACCT_MGMT) { diff --git a/src/providers/krb5/krb5_delayed_online_authentication.c b/src/providers/krb5/krb5_delayed_online_authentication.c index d5dea3bb4c7661f45b6bea83cf803c7d681062cc..f95fa634c34ebee37bffb785abe4ef5b35318a82 100644 --- a/src/providers/krb5/krb5_delayed_online_authentication.c +++ b/src/providers/krb5/krb5_delayed_online_authentication.c @@ -71,27 +71,29 @@ static void authenticate_user(struct tevent_context *ev,
DEBUG_PAM_DATA(9, pd);
- if (pd->authtok == NULL || pd->authtok_size == 0) { - DEBUG(1, ("Missing authtok for user [%s].\n", pd->user)); - return; - } - #ifdef USE_KEYRING + char *password; long keysize; long keyrevoke; - int ret; - keysize = keyctl_read(pd->key_serial, (char *) pd->authtok, - pd->authtok_size); - keyrevoke = keyctl_revoke(pd->key_serial); + errno_t ret; + + keysize = keyctl_read_alloc(pd->key_serial, (void **)&password); if (keysize == -1) { ret = errno; DEBUG(1, ("keyctl_read failed [%d][%s].\n", ret, strerror(ret))); return; - } else if (keysize != pd->authtok_size) { - DEBUG(1, ("keyctl_read returned key with wrong size, " - "expect [%d] got [%d].\n", pd->authtok_size, keysize)); + } + + ret = sss_authtok_set_password(pd, &pd->authtok, password, keysize); + safezero(password, keysize); + free(password); + if (ret) { + DEBUG(1, ("failed to set password in auth token [%d][%s].\n", + ret, strerror(ret))); return; } + + keyrevoke = keyctl_revoke(pd->key_serial); if (keyrevoke == -1) { ret = errno; DEBUG(1, ("keyctl_revoke failed [%d][%s].\n", ret, strerror(ret))); @@ -244,8 +246,8 @@ errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx, return EINVAL; }
- if (pd->authtok_size == 0 || pd->authtok == NULL) { - DEBUG(1, ("Missing authtok for user [%s].\n", pd->user)); + if (sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { + DEBUG(1, ("Invalid authtok for user [%s].\n", pd->user)); return EINVAL; }
@@ -257,17 +259,29 @@ errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx,
#ifdef USE_KEYRING - new_pd->key_serial = add_key("user", new_pd->user, new_pd->authtok, - new_pd->authtok_size, KEY_SPEC_SESSION_KEYRING); + const char *password; + size_t len; + + ret = sss_authtok_get_password(&new_pd->authtok, &password, &len); + if (ret) { + DEBUG(1, ("Failed to get password [%d][%s].\n", ret, strerror(ret))); + sss_authtok_set_empty(&new_pd->authtok); + talloc_free(new_pd); + return ret; + } + + new_pd->key_serial = add_key("user", new_pd->user, password, len, + KEY_SPEC_SESSION_KEYRING); if (new_pd->key_serial == -1) { ret = errno; - DEBUG(1, ("add_key fialed [%d][%s].\n", ret, strerror(ret))); + DEBUG(1, ("add_key failed [%d][%s].\n", ret, strerror(ret))); + sss_authtok_set_empty(&new_pd->authtok); talloc_free(new_pd); return ret; } DEBUG(9, ("Saved authtok of user [%s] with serial [%ld].\n", new_pd->user, new_pd->key_serial)); - memset(new_pd->authtok, 0, new_pd->authtok_size); + sss_authtok_set_empty(&new_pd->authtok); #endif
key.type = HASH_KEY_ULONG; diff --git a/src/providers/krb5/krb5_renew_tgt.c b/src/providers/krb5/krb5_renew_tgt.c index ccb7e6af6d05121292d1152977c319daf660c9ef..4a812ab04d028961914557522423be82a1a01941 100644 --- a/src/providers/krb5/krb5_renew_tgt.c +++ b/src/providers/krb5/krb5_renew_tgt.c @@ -593,22 +593,14 @@ errno_t add_tgt_to_renew_table(struct krb5_ctx *krb5_ctx, const char *ccfile, goto done; }
- if (renew_data->pd->newauthtok_type != SSS_AUTHTOK_TYPE_EMPTY) { - talloc_zfree(renew_data->pd->newauthtok); - renew_data->pd->newauthtok_size = 0; - renew_data->pd->newauthtok_type = SSS_AUTHTOK_TYPE_EMPTY; - } + sss_authtok_set_empty(&renew_data->pd->newauthtok);
- talloc_zfree(renew_data->pd->authtok); - renew_data->pd->authtok = (uint8_t *) talloc_strdup(renew_data->pd, - renew_data->ccfile); - if (renew_data->pd->authtok == NULL) { - DEBUG(1, ("talloc_strdup failed.\n")); - ret = ENOMEM; + ret = sss_authtok_set_ccfile(renew_data->pd, &renew_data->pd->authtok, + renew_data->ccfile, 0); + if (ret) { + DEBUG(1, ("Failed to store ccfile in auth token.\n")); goto done; } - renew_data->pd->authtok_size = strlen((char *) renew_data->pd->authtok) + 1; - renew_data->pd->authtok_type = SSS_AUTHTOK_TYPE_CCFILE;
renew_data->pd->cmd = SSS_CMD_RENEW;
diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c index 32a2e04ea959a3cc81b88f5b2b19575c813e8adf..98483fee0da418523e78152861d489988eb9c6c2 100644 --- a/src/providers/ldap/ldap_auth.c +++ b/src/providers/ldap/ldap_auth.c @@ -462,7 +462,7 @@ struct auth_state { struct tevent_context *ev; struct sdap_auth_ctx *ctx; const char *username; - struct dp_opt_blob password; + struct sss_auth_token *authtok; struct sdap_service *sdap_service;
struct sdap_handle *sh; @@ -484,7 +484,7 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx, struct tevent_context *ev, struct sdap_auth_ctx *ctx, const char *username, - struct dp_opt_blob password, + struct sss_auth_token *authtok, bool try_chpass_service) { struct tevent_req *req; @@ -493,8 +493,8 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx, req = tevent_req_create(memctx, &state, struct auth_state); if (!req) return NULL;
- /* Treat a zero-length password as a failure */ - if (password.length == 0) { + /* The token must be a password token */ + if (sss_authtok_get_type(authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { state->result = SDAP_AUTH_FAILED; tevent_req_done(req); return tevent_req_post(req, ev); @@ -503,7 +503,7 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx, state->ev = ev; state->ctx = ctx; state->username = username; - state->password = password; + state->authtok = authtok; state->srv = NULL; if (try_chpass_service && ctx->chpass_service != NULL && ctx->chpass_service->name != NULL) { @@ -632,7 +632,7 @@ static void auth_connect_done(struct tevent_req *subreq)
subreq = sdap_auth_send(state, state->ev, state->sh, NULL, NULL, state->dn, - "password", state->password); + state->authtok); if (!subreq) { tevent_req_error(req, ENOMEM); return; @@ -727,8 +727,6 @@ struct sdap_pam_chpass_state { struct pam_data *pd; const char *username; char *dn; - char *password; - char *new_password; struct sdap_handle *sh;
struct sdap_auth_ctx *ctx; @@ -744,7 +742,6 @@ void sdap_pam_chpass_handler(struct be_req *breq) struct sdap_auth_ctx *ctx; struct tevent_req *subreq; struct pam_data *pd; - struct dp_opt_blob authtok; int dp_err = DP_ERR_FATAL;
ctx = talloc_get_type(breq->be_ctx->bet_info[BET_CHPASS].pvt_bet_data, @@ -758,8 +755,8 @@ void sdap_pam_chpass_handler(struct be_req *breq) goto done; }
- if (pd->priv == 1 && pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM && - pd->authtok_size == 0) { + if ((pd->priv == 1) && (pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) && + (sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD)) { DEBUG(4, ("Password reset by root is not supported.\n")); pd->pam_status = PAM_PERM_DENIED; dp_err = DP_ERR_OK; @@ -782,25 +779,9 @@ void sdap_pam_chpass_handler(struct be_req *breq) state->pd = pd; state->username = pd->user; state->ctx = ctx; - state->password = talloc_strndup(state, - (char *)pd->authtok, pd->authtok_size); - if (!state->password) goto done; - talloc_set_destructor((TALLOC_CTX *)state->password, - password_destructor);
- if (pd->cmd == SSS_PAM_CHAUTHTOK) { - state->new_password = talloc_strndup(state, - (char *)pd->newauthtok, - pd->newauthtok_size); - if (!state->new_password) goto done; - talloc_set_destructor((TALLOC_CTX *)state->new_password, - password_destructor); - } - - authtok.data = (uint8_t *)state->password; - authtok.length = strlen(state->password); - subreq = auth_send(breq, breq->be_ctx->ev, - ctx, state->username, authtok, true); + subreq = auth_send(breq, breq->be_ctx->ev, ctx, + state->username, &pd->authtok, true); if (!subreq) goto done;
tevent_req_set_callback(subreq, sdap_auth4chpass_done, state); @@ -887,18 +868,30 @@ static void sdap_auth4chpass_done(struct tevent_req *req) state->pd->pam_status = PAM_MODULE_UNKNOWN; goto done; } else { + const char *password; + const char *new_password; + + ret = sss_authtok_get_password(&state->pd->authtok, + &password, NULL); + if (ret) { + state->pd->pam_status = PAM_SYSTEM_ERR; + goto done; + } + ret = sss_authtok_get_password(&state->pd->newauthtok, + &new_password, NULL); + if (ret) { + state->pd->pam_status = PAM_SYSTEM_ERR; + goto done; + } + subreq = sdap_exop_modify_passwd_send(state, state->breq->be_ctx->ev, - state->sh, - state->dn, - state->password, - state->new_password); - + state->sh, state->dn, + password, new_password); if (!subreq) { DEBUG(2, ("Failed to change password for %s\n", state->username)); goto done; } - tevent_req_set_callback(subreq, sdap_pam_chpass_done, state); return; } @@ -1013,8 +1006,6 @@ done: struct sdap_pam_auth_state { struct be_req *breq; struct pam_data *pd; - const char *username; - struct dp_opt_blob password; };
static void sdap_pam_auth_done(struct tevent_req *req); @@ -1049,12 +1040,9 @@ void sdap_pam_auth_handler(struct be_req *breq)
state->breq = breq; state->pd = pd; - state->username = pd->user; - state->password.data = pd->authtok; - state->password.length = pd->authtok_size;
subreq = auth_send(breq, breq->be_ctx->ev, ctx, - state->username, state->password, + pd->user, &pd->authtok, pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM ? true : false); if (!subreq) goto done;
@@ -1088,6 +1076,7 @@ static void sdap_pam_auth_done(struct tevent_req *req) enum pwexpire pw_expire_type; struct be_ctx *be_ctx = state->breq->be_ctx; void *pw_expire_data; + const char *password; int dp_err = DP_ERR_OK; int ret;
@@ -1170,26 +1159,19 @@ static void sdap_pam_auth_done(struct tevent_req *req) if (result == SDAP_AUTH_SUCCESS && state->breq->be_ctx->domain->cache_credentials) {
- char *password = talloc_strndup(state, (char *) - state->password.data, - state->password.length); - /* password caching failures are not fatal errors */ - if (!password) { - DEBUG(2, ("Failed to cache password for %s\n", state->username)); - goto done; + ret = sss_authtok_get_password(&state->pd->authtok, &password, NULL); + if (ret == EOK) { + ret = sysdb_cache_password(state->breq->be_ctx->sysdb, + state->pd->user, password); } - talloc_set_destructor((TALLOC_CTX *)password, password_destructor); - - ret = sysdb_cache_password(state->breq->be_ctx->sysdb, - state->username, password);
/* password caching failures are not fatal errors */ if (ret != EOK) { DEBUG(2, ("Failed to cache password for %s\n", - state->username)); + state->pd->user)); } else { DEBUG(4, ("Password successfully cached for %s\n", - state->username)); + state->pd->user)); } goto done; } diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c index e0440625d279fbbaa1cc2e6343b73f5a247371f7..84497b75ef586b58e27cc4dc9e6b8b3244464676 100644 --- a/src/providers/ldap/sdap_async.c +++ b/src/providers/ldap/sdap_async.c @@ -502,8 +502,8 @@ struct tevent_req *sdap_exop_modify_passwd_send(TALLOC_CTX *memctx, struct tevent_context *ev, struct sdap_handle *sh, char *user_dn, - char *password, - char *new_password) + const char *password, + const char *new_password) { struct tevent_req *req = NULL; struct sdap_exop_modify_passwd_state *state; diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h index 8c16d94e6486336e92b6112cd8b5a2dff4c97957..c5dc17037cd6d2c4ae88aa60d43d517eb2958085 100644 --- a/src/providers/ldap/sdap_async.h +++ b/src/providers/ldap/sdap_async.h @@ -108,8 +108,7 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, const char *sasl_mech, const char *sasl_user, const char *user_dn, - const char *authtok_type, - struct dp_opt_blob authtok); + struct sss_auth_token *authtok);
int sdap_auth_recv(struct tevent_req *req, TALLOC_CTX *memctx, @@ -128,8 +127,8 @@ struct tevent_req *sdap_exop_modify_passwd_send(TALLOC_CTX *memctx, struct tevent_context *ev, struct sdap_handle *sh, char *user_dn, - char *password, - char *new_password); + const char *password, + const char *new_password); int sdap_exop_modify_passwd_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, enum sdap_result *result, char **user_error_msg); diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c index 79ad3b8e4c7720982944e502c4424d61dd1f1295..8899e2944808cf6a0ea6c10bb6bc2de46702b106 100644 --- a/src/providers/ldap/sdap_async_connection.c +++ b/src/providers/ldap/sdap_async_connection.c @@ -493,7 +493,7 @@ static struct tevent_req *simple_bind_send(TALLOC_CTX *memctx, DEBUG(4, ("Executing simple bind as: %s\n", state->user_dn));
ret = ldap_sasl_bind(state->sh->ldap, state->user_dn, LDAP_SASL_SIMPLE, - state->pw, request_controls, NULL, &msgid); + pw, request_controls, NULL, &msgid); if (ctrls[0]) ldap_control_free(ctrls[0]); if (ret == -1 || msgid == -1) { ret = ldap_get_option(state->sh->ldap, @@ -1082,18 +1082,12 @@ int sdap_kinit_recv(struct tevent_req *req, /* ==Authenticaticate-User-by-DN========================================== */
struct sdap_auth_state { - const char *user_dn; - struct berval pw; struct sdap_ppolicy_data *ppolicy; - - int result; bool is_sasl; + int result; };
static void sdap_auth_done(struct tevent_req *subreq); -static int sdap_auth_get_authtok(const char *authtok_type, - struct dp_opt_blob authtok, - struct berval *pw);
/* TODO: handle sasl_cred */ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, @@ -1102,31 +1096,14 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, const char *sasl_mech, const char *sasl_user, const char *user_dn, - const char *authtok_type, - struct dp_opt_blob authtok) + struct sss_auth_token *authtok) { struct tevent_req *req, *subreq; struct sdap_auth_state *state; - int ret;
req = tevent_req_create(memctx, &state, struct sdap_auth_state); if (!req) return NULL;
- state->user_dn = user_dn; - - ret = sdap_auth_get_authtok(authtok_type, authtok, &state->pw); - if (ret != EOK) { - if (ret == ENOSYS) { - DEBUG(1, ("Getting authtok is not supported with the " - "crypto library compiled with, authentication " - "might fail!\n")); - } else { - DEBUG(1, ("Cannot parse authtok.\n")); - tevent_req_error(req, ret); - return tevent_req_post(req, ev); - } - } - if (sasl_mech) { state->is_sasl = true; subreq = sasl_bind_send(state, ev, sh, sasl_mech, sasl_user, NULL); @@ -1135,8 +1112,27 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, return tevent_req_post(req, ev); } } else { + const char *password = NULL; + struct berval pw; + size_t pwlen; + errno_t ret; + + ret = sss_authtok_get_password(authtok, &password, &pwlen); + if (ret != EOK) { + DEBUG(1, ("Cannot parse authtok.\n")); + tevent_req_error(req, ret); + return tevent_req_post(req, ev); + } + /* Treat a zero-length password as a failure */ + if (*password == '\0') { + tevent_req_error(req, ENOENT); + return tevent_req_post(req, ev); + } + pw.bv_val = discard_const(password); + pw.bv_len = pwlen - 1; + state->is_sasl = false; - subreq = simple_bind_send(state, ev, sh, user_dn, &state->pw); + subreq = simple_bind_send(state, ev, sh, user_dn, &pw); if (!subreq) { tevent_req_error(req, ENOMEM); return tevent_req_post(req, ev); @@ -1598,6 +1594,10 @@ static void sdap_cli_auth_step(struct tevent_req *req) SDAP_SASL_MECH); const char *user_dn = dp_opt_get_string(state->opts->basic, SDAP_DEFAULT_BIND_DN); + const char *authtok_type; + struct dp_opt_blob authtok_blob; + struct sss_auth_token authtok = { 0 }; + errno_t ret;
if (!state->do_auth || (sasl_mech == NULL && user_dn == NULL)) { @@ -1617,17 +1617,31 @@ static void sdap_cli_auth_step(struct tevent_req *req) state->sh->expire_time = now + expire_timeout; }
- subreq = sdap_auth_send(state, - state->ev, - state->sh, - sasl_mech, + authtok_type = dp_opt_get_string(state->opts->basic, + SDAP_DEFAULT_AUTHTOK_TYPE); + if (authtok_type != NULL) { + if (strcasecmp(authtok_type, "password") != 0) { + DEBUG(SSSDBG_TRACE_LIBS, ("Invalid authtoken type\n")); + tevent_req_error(req, EINVAL); + return; + } + authtok_blob = dp_opt_get_blob(state->opts->basic, + SDAP_DEFAULT_AUTHTOK); + + ret = sss_authtok_set_password(state, &authtok, + (const char *)authtok_blob.data, + authtok_blob.length); + if (ret) { + tevent_req_error(req, ret); + return; + } + } + + subreq = sdap_auth_send(state, state->ev, + state->sh, sasl_mech, dp_opt_get_string(state->opts->basic, - SDAP_SASL_AUTHID), - user_dn, - dp_opt_get_string(state->opts->basic, - SDAP_DEFAULT_AUTHTOK_TYPE), - dp_opt_get_blob(state->opts->basic, - SDAP_DEFAULT_AUTHTOK)); + SDAP_SASL_AUTHID), + user_dn, &authtok); if (!subreq) { tevent_req_error(req, ENOMEM); return; diff --git a/src/providers/proxy/proxy.h b/src/providers/proxy/proxy.h index cea03382517231cdf2b96069ab93dfb7967b46a6..962cb28fc7d6362c45d268f289ffbce103a6e738 100644 --- a/src/providers/proxy/proxy.h +++ b/src/providers/proxy/proxy.h @@ -89,11 +89,8 @@ struct proxy_nss_ops { };
struct authtok_conv { - uint32_t authtok_size; - uint8_t *authtok; - - uint32_t newauthtok_size; - uint8_t *newauthtok; + struct sss_auth_token authtok; + struct sss_auth_token newauthtok;
bool sent_old; }; diff --git a/src/providers/proxy/proxy_auth.c b/src/providers/proxy/proxy_auth.c index 8088283fa8147f75b7d8eb4c83c63208163c9375..3430f38b282eff2da24735f8d635a952edde8888 100644 --- a/src/providers/proxy/proxy_auth.c +++ b/src/providers/proxy/proxy_auth.c @@ -712,7 +712,7 @@ static void proxy_child_done(struct tevent_req *req) struct proxy_client_ctx *client_ctx = tevent_req_callback_data(req, struct proxy_client_ctx); struct pam_data *pd = NULL; - char *password; + const char *password; int ret; struct tevent_immediate *imm;
@@ -747,17 +747,15 @@ static void proxy_child_done(struct tevent_req *req)
/* Check if we need to save the cached credentials */ if ((pd->cmd == SSS_PAM_AUTHENTICATE || pd->cmd == SSS_PAM_CHAUTHTOK) && - pd->pam_status == PAM_SUCCESS && - client_ctx->be_req->be_ctx->domain->cache_credentials) { - password = talloc_strndup(client_ctx->be_req, - (char *) pd->authtok, - pd->authtok_size); - if (!password) { + (pd->pam_status == PAM_SUCCESS) && + client_ctx->be_req->be_ctx->domain->cache_credentials) { + + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + if (ret) { /* password caching failures are not fatal errors */ DEBUG(2, ("Failed to cache password\n")); goto done; } - talloc_set_destructor((TALLOC_CTX *)password, password_destructor);
ret = sysdb_cache_password(client_ctx->be_req->be_ctx->sysdb, pd->user, password); diff --git a/src/providers/proxy/proxy_child.c b/src/providers/proxy/proxy_child.c index c575948a7036d9b73d93bd00e111834b12d28e7d..556dbf9b5488d75f0fa60386958f61b95d61fba2 100644 --- a/src/providers/proxy/proxy_child.c +++ b/src/providers/proxy/proxy_child.c @@ -80,6 +80,9 @@ static int proxy_internal_conv(int num_msg, const struct pam_message **msgm, int i; struct pam_response *reply; struct authtok_conv *auth_data; + const char *password; + size_t pwlen; + errno_t ret;
auth_data = talloc_get_type(appdata_ptr, struct authtok_conv);
@@ -94,11 +97,13 @@ static int proxy_internal_conv(int num_msg, const struct pam_message **msgm, case PAM_PROMPT_ECHO_OFF: DEBUG(4, ("Conversation message: [%s]\n", msgm[i]->msg)); reply[i].resp_retcode = 0; - reply[i].resp = calloc(auth_data->authtok_size + 1, - sizeof(char)); + + ret = sss_authtok_get_password(&auth_data->authtok, + &password, &pwlen); + if (ret) goto failed; + reply[i].resp = calloc(pwlen + 1, sizeof(char)); if (reply[i].resp == NULL) goto failed; - memcpy(reply[i].resp, auth_data->authtok, - auth_data->authtok_size); + memcpy(reply[i].resp, password, pwlen + 1);
break; default: @@ -124,6 +129,9 @@ static int proxy_chauthtok_conv(int num_msg, const struct pam_message **msgm, int i; struct pam_response *reply; struct authtok_conv *auth_data; + const char *password; + size_t pwlen; + errno_t ret;
auth_data = talloc_get_type(appdata_ptr, struct authtok_conv);
@@ -141,20 +149,23 @@ static int proxy_chauthtok_conv(int num_msg, const struct pam_message **msgm, reply[i].resp_retcode = 0; if (!auth_data->sent_old) { /* The first prompt will be asking for the old authtok */ - reply[i].resp = calloc(auth_data->authtok_size + 1, - sizeof(char)); + ret = sss_authtok_get_password(&auth_data->authtok, + &password, &pwlen); + if (ret) goto failed; + reply[i].resp = calloc(pwlen + 1, sizeof(char)); if (reply[i].resp == NULL) goto failed; - memcpy(reply[i].resp, auth_data->authtok, - auth_data->authtok_size); + memcpy(reply[i].resp, password, pwlen + 1); auth_data->sent_old = true; } else { /* Subsequent prompts are looking for the new authtok */ - reply[i].resp = calloc(auth_data->newauthtok_size + 1, - sizeof(char)); + ret = sss_authtok_get_password(&auth_data->newauthtok, + &password, &pwlen); + if (ret) goto failed; + reply[i].resp = calloc(pwlen + 1, sizeof(char)); if (reply[i].resp == NULL) goto failed; - memcpy(reply[i].resp, auth_data->newauthtok, - auth_data->newauthtok_size); + memcpy(reply[i].resp, password, pwlen + 1); + auth_data->sent_old = true; }
break; @@ -213,8 +224,8 @@ static errno_t call_pam_stack(const char *pam_target, struct pam_data *pd) } switch (pd->cmd) { case SSS_PAM_AUTHENTICATE: - auth_data->authtok_size = pd->authtok_size; - auth_data->authtok = pd->authtok; + sss_authtok_copy(auth_data, &pd->authtok, + &auth_data->authtok); pam_status = pam_authenticate(pamh, 0); break; case SSS_PAM_SETCRED: @@ -230,21 +241,21 @@ static errno_t call_pam_stack(const char *pam_target, struct pam_data *pd) pam_status=pam_close_session(pamh, 0); break; case SSS_PAM_CHAUTHTOK: - auth_data->authtok_size = pd->authtok_size; - auth_data->authtok = pd->authtok; + sss_authtok_copy(auth_data, &pd->authtok, + &auth_data->authtok); if (pd->priv != 1) { pam_status = pam_authenticate(pamh, 0); auth_data->sent_old = false; if (pam_status != PAM_SUCCESS) break; } - auth_data->newauthtok_size = pd->newauthtok_size; - auth_data->newauthtok = pd->newauthtok; + sss_authtok_copy(auth_data, &pd->newauthtok, + &auth_data->newauthtok); pam_status = pam_chauthtok(pamh, 0); break; case SSS_PAM_CHAUTHTOK_PRELIM: if (pd->priv != 1) { - auth_data->authtok_size = pd->authtok_size; - auth_data->authtok = pd->authtok; + sss_authtok_copy(auth_data, &pd->authtok, + &auth_data->authtok); pam_status = pam_authenticate(pamh, 0); } else { pam_status = PAM_SUCCESS; diff --git a/src/responder/pam/pam_LOCAL_domain.c b/src/responder/pam/pam_LOCAL_domain.c index 71446b4f8da53bfe4c0707621fafb228da5f808c..23eb7a2a8ddd3ae4480030633be867564b7f59f2 100644 --- a/src/responder/pam/pam_LOCAL_domain.c +++ b/src/responder/pam/pam_LOCAL_domain.c @@ -154,22 +154,19 @@ static void do_pam_acct_mgmt(struct LOCAL_request *lreq) static void do_pam_chauthtok(struct LOCAL_request *lreq) { int ret; - char *newauthtok; + const char *password; char *salt; char *new_hash; struct pam_data *pd;
pd = lreq->preq->pd;
- newauthtok = talloc_strndup(lreq, (char *) pd->newauthtok, - pd->newauthtok_size); - NULL_CHECK_OR_JUMP(newauthtok, ("talloc_strndup failed.\n"), lreq->error, - ENOMEM, done); - memset(pd->newauthtok, 0, pd->newauthtok_size); - - if (strlen(newauthtok) == 0) { + ret = sss_authtok_get_password(&pd->newauthtok, &password, NULL); + if (ret) { /* TODO: should we allow null passwords via a config option ? */ - DEBUG(1, ("Empty passwords are not allowed!\n")); + if (ret == ENOENT) { + DEBUG(1, ("Empty passwords are not allowed!\n")); + } lreq->error = EINVAL; goto done; } @@ -179,11 +176,10 @@ static void do_pam_chauthtok(struct LOCAL_request *lreq) lreq->error, ret, done); DEBUG(4, ("Using salt [%s]\n", salt));
- ret = s3crypt_sha512(lreq, newauthtok, salt, &new_hash); + ret = s3crypt_sha512(lreq, password, salt, &new_hash); NEQ_CHECK_OR_JUMP(ret, EOK, ("Hash generation failed.\n"), lreq->error, ret, done); DEBUG(4, ("New hash [%s]\n", new_hash)); - memset(newauthtok, 0, pd->newauthtok_size);
lreq->mod_attrs = sysdb_new_attrs(lreq); NULL_CHECK_OR_JUMP(lreq->mod_attrs, ("sysdb_new_attrs failed.\n"), @@ -204,7 +200,7 @@ static void do_pam_chauthtok(struct LOCAL_request *lreq) lreq->error, ret, done);
done: - return; + sss_authtok_set_empty(&pd->newauthtok); }
int LOCAL_pam_handler(struct pam_auth_req *preq) @@ -223,9 +219,9 @@ int LOCAL_pam_handler(struct pam_auth_req *preq) NULL}; struct ldb_result *res; const char *username = NULL; - const char *password = NULL; + const char *pwdhash = NULL; char *new_hash = NULL; - char *authtok = NULL; + const char *password; struct pam_data *pd = preq->pd; int ret;
@@ -287,25 +283,22 @@ int LOCAL_pam_handler(struct pam_auth_req *preq) DEBUG(4, ("allowing root to reset a password.\n")); break; } - authtok = talloc_strndup(lreq, (char *) pd->authtok, - pd->authtok_size); - NULL_CHECK_OR_JUMP(authtok, ("talloc_strndup failed.\n"), - lreq->error, ENOMEM, done); - memset(pd->authtok, 0, pd->authtok_size); + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + NEQ_CHECK_OR_JUMP(ret, EOK, ("Failed to get password.\n"), + lreq->error, ret, done);
- password = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_PWD, NULL); - NULL_CHECK_OR_JUMP(password, ("No password stored.\n"), + pwdhash = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_PWD, NULL); + NULL_CHECK_OR_JUMP(pwdhash, ("No password stored.\n"), lreq->error, LDB_ERR_NO_SUCH_ATTRIBUTE, done); - DEBUG(4, ("user: [%s], password hash: [%s]\n", username, password)); + DEBUG(4, ("user: [%s], password hash: [%s]\n", username, pwdhash));
- ret = s3crypt_sha512(lreq, authtok, password, &new_hash); - memset(authtok, 0, pd->authtok_size); + ret = s3crypt_sha512(lreq, password, pwdhash, &new_hash); NEQ_CHECK_OR_JUMP(ret, EOK, ("nss_sha512_crypt failed.\n"), lreq->error, ret, done);
DEBUG(4, ("user: [%s], new hash: [%s]\n", username, new_hash));
- if (strcmp(new_hash, password) != 0) { + if (strcmp(new_hash, pwdhash) != 0) { DEBUG(1, ("Passwords do not match.\n")); do_failed_login(lreq); goto done; @@ -338,13 +331,8 @@ int LOCAL_pam_handler(struct pam_auth_req *preq) }
done: - if (pd->authtok != NULL) - memset(pd->authtok, 0, pd->authtok_size); - if (authtok != NULL) - memset(authtok, 0, pd->authtok_size); - if (pd->newauthtok != NULL) - memset(pd->newauthtok, 0, pd->newauthtok_size); - + sss_authtok_set_empty(&pd->newauthtok); + sss_authtok_set_empty(&pd->authtok); prepare_reply(lreq); return EOK; } diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index 8ab90e30e3f553c95a43db3ce69799b8b6d24d76..689155fa32bbf63f707c9d830d46cf586c940bbf 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -48,21 +48,38 @@ enum pam_verbosity {
static void pam_reply(struct pam_auth_req *preq);
-static int extract_authtok(uint32_t *type, uint32_t *size, uint8_t **tok, - size_t data_size, uint8_t *body, size_t blen, - size_t *c) { +static int extract_authtok_v2(TALLOC_CTX *mem_ctx, struct sss_auth_token *tok, + size_t data_size, uint8_t *body, size_t blen, + size_t *c) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + uint8_t *auth_token_data; + int ret = EOK;
if (data_size < sizeof(uint32_t) || *c+data_size > blen || SIZE_T_OVERFLOW(*c, data_size)) return EINVAL; - *size = data_size - sizeof(uint32_t);
- SAFEALIGN_COPY_UINT32_CHECK(type, &body[*c], blen, c); + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, &body[*c], blen, c); + auth_token_length = data_size - sizeof(uint32_t); + auth_token_data = body+(*c);
- *tok = body+(*c); + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_set_password(mem_ctx, tok, + (const char *)auth_token_data, + auth_token_length); + break; + default: + return EINVAL; + }
- *c += (*size); + *c += auth_token_length;
- return EOK; + return ret; }
static int extract_string(char **var, size_t size, uint8_t *body, size_t blen, @@ -184,14 +201,13 @@ static int pam_parse_in_data_v2(struct sss_domain_info *domains, if (ret != EOK) return ret; break; case SSS_PAM_ITEM_AUTHTOK: - ret = extract_authtok(&pd->authtok_type, &pd->authtok_size, - &pd->authtok, size, body, blen, &c); + ret = extract_authtok_v2(pd, &pd->authtok, + size, body, blen, &c); if (ret != EOK) return ret; break; case SSS_PAM_ITEM_NEWAUTHTOK: - ret = extract_authtok(&pd->newauthtok_type, - &pd->newauthtok_size, - &pd->newauthtok, size, body, blen, &c); + ret = extract_authtok_v2(pd, &pd->newauthtok, + size, body, blen, &c); if (ret != EOK) return ret; break; default: @@ -231,14 +247,44 @@ static int pam_parse_in_data_v3(struct sss_domain_info *domains, return EOK; }
+static int extract_authtok_v1(TALLOC_CTX *mem_ctx, struct sss_auth_token *tok, + uint8_t *body, size_t blen, size_t *c) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + uint8_t *auth_token_data; + int ret = EOK; + + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, &body[*c], blen, c); + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_length, &body[*c], blen, c); + auth_token_data = body+(*c); + + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_set_password(mem_ctx, tok, + (const char *)auth_token_data, + auth_token_length); + break; + default: + return EINVAL; + } + + *c += auth_token_length; + + return ret; +} + static int pam_parse_in_data(struct sss_domain_info *domains, const char *default_domain, struct pam_data *pd, uint8_t *body, size_t blen) { - int start; - int end; - int last; + size_t start; + size_t end; + size_t last; int ret;
last = blen - 1; @@ -268,45 +314,15 @@ static int pam_parse_in_data(struct sss_domain_info *domains, if (body[end++] != '\0') return EINVAL; pd->rhost = (char *) &body[start];
- start = end; - pd->authtok_type = (int) body[start]; - - start += sizeof(uint32_t); - pd->authtok_size = (int) body[start]; - if (pd->authtok_size >= blen) return EINVAL; - - start += sizeof(uint32_t); - end = start + pd->authtok_size; - if (pd->authtok_size == 0) { - pd->authtok = NULL; - } else { - if (end <= blen) { - pd->authtok = (uint8_t *) &body[start]; - } else { - DEBUG(1, ("Invalid authtok size: %d\n", pd->authtok_size)); - return EINVAL; - } + ret = extract_authtok_v1(pd, &pd->authtok, body, blen, &end); + if (ret) { + DEBUG(1, ("Invalid auth token\n")); + return ret; } - - start = end; - pd->newauthtok_type = (int) body[start]; - - start += sizeof(uint32_t); - pd->newauthtok_size = (int) body[start]; - if (pd->newauthtok_size >= blen) return EINVAL; - - start += sizeof(uint32_t); - end = start + pd->newauthtok_size; - - if (pd->newauthtok_size == 0) { - pd->newauthtok = NULL; - } else { - if (end <= blen) { - pd->newauthtok = (uint8_t *) &body[start]; - } else { - DEBUG(1, ("Invalid newauthtok size: %d\n", pd->newauthtok_size)); - return EINVAL; - } + ret = extract_authtok_v1(pd, &pd->newauthtok, body, blen, &end); + if (ret) { + DEBUG(1, ("Invalid new auth token\n")); + return ret; }
DEBUG_PAM_DATA(4, pd); @@ -761,9 +777,9 @@ static void pam_reply(struct pam_auth_req *preq) goto done; }
- password = talloc_strndup(preq, pd->authtok, pd->authtok_size); - if (!password) { - DEBUG(0, ("Fatal: Out of memory copying password\n")); + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + if (ret) { + DEBUG(0, ("Failed to get password.\n")); goto done; }
@@ -773,10 +789,6 @@ static void pam_reply(struct pam_auth_req *preq) &exp_date, &delay_until);
pam_cache_auth_done(preq, ret, exp_date, delay_until); - if (password) { - for (i = 0; password[i]; i++) password[i] = 0; - talloc_zfree(password); - } return; } break; diff --git a/src/tests/krb5_child-test.c b/src/tests/krb5_child-test.c index 34d025b77b27a27e6131c1895c6c02644f921e5d..a72a3519985292456db6b9bbf9bccdcf678068a6 100644 --- a/src/tests/krb5_child-test.c +++ b/src/tests/krb5_child-test.c @@ -167,6 +167,9 @@ create_dummy_pam_data(TALLOC_CTX *mem_ctx, const char *user, const char *password) { struct pam_data *pd; + const char *authtok; + size_t authtok_len; + errno_t ret;
pd = talloc_zero(mem_ctx, struct pam_data); if (!pd) goto fail; @@ -175,12 +178,12 @@ create_dummy_pam_data(TALLOC_CTX *mem_ctx, const char *user, pd->user = talloc_strdup(pd, user); if (!pd->user) goto fail;
- pd->authtok = discard_const(talloc_strdup(pd, password)); - if (!pd->authtok) goto fail; - pd->authtok_size = strlen(password); - pd->authtok_type = SSS_AUTHTOK_TYPE_PASSWORD; + ret = sss_authtok_set_password(pd, &pd->authtok, password, 0); + if (ret) goto fail; + + (void)sss_authtok_get_password(&pd->authtok, &authtok, &authtok_len); DEBUG(SSSDBG_FUNC_DATA, ("Authtok [%s] len [%d]\n", - pd->authtok, pd->authtok_size)); + authtok, (int)authtok_len));
return pd;
NOTE: this is just a rebase due to the dependency on the previous patcheset for which some changes were requested,
The current way we handle with auth token is manual and very error prone. The semanthics are also confusing and do not make clear how tokens are stored such that manipulating them is difficult. For example it was unclar in the code whether password tokens where 0 terminated and whether the length would incliude the null termination byte or not.
This code creates a standard structure called sss_auth_token that has a full set of getters and setters.
This patchset depends on the previous patchset I sent that fixes various tevent_req style issues.
It has been tested by performing PAM authentication requests using a kerberos based backend (IPA + AD trust), which should excercise most code paths where it is used.
Note: I wanted to make this structure completely opaque but it would have required a lot more allocations and pointers, and made the patchset larger.
Fixes: https://fedorahosted.org/sssd/ticket/1586
Simo.
Simo Sorce (4): Code can only check for cached passwords Add function to safely wipe memory. Add authtok utility functions. Change pam data auth tokens.
Makefile.am | 4 + src/db/sysdb.h | 3 +- src/db/sysdb_ops.c | 13 +-- src/providers/data_provider.h | 9 +- src/providers/dp_auth_util.c | 76 +++++--- src/providers/dp_pam_data_util.c | 113 ++++++------ src/providers/ipa/ipa_auth.c | 6 +- src/providers/krb5/krb5_auth.c | 52 +++--- src/providers/krb5/krb5_child.c | 148 ++++++++------- src/providers/krb5/krb5_child_handler.c | 59 +++++- .../krb5/krb5_delayed_online_authentication.c | 50 ++++-- src/providers/krb5/krb5_renew_tgt.c | 18 +-- src/providers/ldap/ldap_auth.c | 90 ++++------ src/providers/ldap/sdap_async.c | 4 +- src/providers/ldap/sdap_async.h | 7 +- src/providers/ldap/sdap_async_connection.c | 88 +++++---- src/providers/proxy/proxy.h | 7 +- src/providers/proxy/proxy_auth.c | 14 +- src/providers/proxy/proxy_child.c | 51 +++-- src/responder/pam/pam_LOCAL_domain.c | 52 ++---- src/responder/pam/pamsrv_cmd.c | 159 +++++++++------- src/tests/krb5_child-test.c | 13 +- src/tests/sysdb-tests.c | 6 +- src/util/authtok.c | 195 ++++++++++++++++++++ src/util/authtok.h | 180 ++++++++++++++++++ src/util/util.c | 9 + src/util/util.h | 10 + 27 files changed, 951 insertions(+), 485 deletions(-) create mode 100644 src/util/authtok.c create mode 100644 src/util/authtok.h
Make it clear to the API users that we can not take arbitrary auth tokens. We can only take a password for now so simplify and clarify the interface. --- src/db/sysdb.h | 3 +-- src/db/sysdb_ops.c | 12 +----------- src/providers/krb5/krb5_auth.c | 23 ++++++++++++++++++----- src/responder/pam/pamsrv_cmd.c | 39 ++++++++++++++++++++++++--------------- src/tests/sysdb-tests.c | 6 ++---- 5 files changed, 46 insertions(+), 37 deletions(-)
diff --git a/src/db/sysdb.h b/src/db/sysdb.h index 8fe0e81c1a98834ea70484d8ec67a4b397b9e2b9..e65bffa413998fc9564a78970a689998406ea0ef 100644 --- a/src/db/sysdb.h +++ b/src/db/sysdb.h @@ -750,8 +750,7 @@ errno_t check_failed_login_attempts(struct confdb_ctx *cdb, time_t *delayed_until); int sysdb_cache_auth(struct sysdb_ctx *sysdb, const char *name, - const uint8_t *authtok, - size_t authtok_size, + const char *password, struct confdb_ctx *cdb, bool just_check, time_t *_expire_date, diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c index 52f0cef54b9819b1f5d754dcbd56abd1d7cb0e96..9f476e98ef0c09f39659d52b927224a20e42db07 100644 --- a/src/db/sysdb_ops.c +++ b/src/db/sysdb_ops.c @@ -2654,8 +2654,7 @@ done:
int sysdb_cache_auth(struct sysdb_ctx *sysdb, const char *name, - const uint8_t *authtok, - size_t authtok_size, + const char *password, struct confdb_ctx *cdb, bool just_check, time_t *_expire_date, @@ -2670,7 +2669,6 @@ int sysdb_cache_auth(struct sysdb_ctx *sysdb, struct ldb_message *ldb_msg; const char *userhash; char *comphash; - char *password = NULL; uint64_t lastLogin = 0; int cred_expiration; uint32_t failed_login_attempts = 0; @@ -2756,13 +2754,6 @@ int sysdb_cache_auth(struct sysdb_ctx *sysdb,
/* TODO: verify user account (disabled, expired ...) */
- password = talloc_strndup(tmp_ctx, (const char *)authtok, authtok_size); - if (password == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - ret = ENOMEM; - goto done; - } - userhash = ldb_msg_find_attr_as_string(ldb_msg, SYSDB_CACHEDPWD, NULL); if (userhash == NULL || *userhash == '\0') { DEBUG(4, ("Cached credentials not available.\n")); @@ -2846,7 +2837,6 @@ done: if (_delayed_until != NULL) { *_delayed_until = delayed_until; } - if (password) for (i = 0; password[i]; i++) password[i] = 0; if (ret) { ldb_transaction_cancel(sysdb->ldb); } else { diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c index e0fe7e71b164a9726832950756c34534ceb22a73..5553abd76c7f0e1717a9cf31c76bda0370174f40 100644 --- a/src/providers/krb5/krb5_auth.c +++ b/src/providers/krb5/krb5_auth.c @@ -277,16 +277,23 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, struct pam_data *pd, uid_t uid, int *pam_status, int *dp_err) { + char *password = NULL; errno_t ret;
- ret = sysdb_cache_auth(sysdb, pd->user, pd->authtok, - pd->authtok_size, cdb, true, NULL, - NULL); + password = talloc_strndup(state, pd->authtok, pd->authtok_size); + if (!password) { + DEBUG(0, ("Out of memory copying password\n")); + *pam_status = PAM_SYSTEM_ERR; + *dp_err = DP_ERR_OK; + return; + } + + ret = sysdb_cache_auth(sysdb, pd->user, password, cdb, true, NULL, NULL); if (ret != EOK) { DEBUG(1, ("Offline authentication failed\n")); *pam_status = PAM_SYSTEM_ERR; *dp_err = DP_ERR_OK; - return; + goto done; }
ret = add_user_to_delayed_online_authentication(krb5_ctx, pd, uid); @@ -296,6 +303,12 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, } *pam_status = PAM_AUTHINFO_UNAVAIL; *dp_err = DP_ERR_OFFLINE; + +done: + if (password) { + for (i = 0; password[i]; i++) password[i] = 0; + talloc_zfree(password); + } }
static errno_t krb5_auth_prepare_ccache_file(struct krb5child_req *kr, diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index bb0d8db384cbbc8a3beed5dc5be0fe32956992a9..b95553b3d7da51127ca7614ebdf062bd45c484cf 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -732,7 +732,6 @@ static void pam_reply(struct pam_auth_req *preq) struct timeval tv; struct tevent_timer *te; struct pam_data *pd; - struct sysdb_ctx *sysdb; struct pam_ctx *pctx; uint32_t user_info_type; time_t exp_date = -1; @@ -752,24 +751,34 @@ static void pam_reply(struct pam_auth_req *preq) if ((preq->domain != NULL) && (preq->domain->cache_credentials == true) && (pd->offline_auth == false)) { + const char *password = NULL;
- /* do auth with offline credentials */ - pd->offline_auth = true; + /* do auth with offline credentials */ + pd->offline_auth = true;
- sysdb = preq->domain->sysdb; - if (sysdb == NULL) { - DEBUG(0, ("Fatal: Sysdb CTX not found for " - "domain [%s]!\n", preq->domain->name)); - goto done; - } + if (preq->domain->sysdb == NULL) { + DEBUG(0, ("Fatal: Sysdb CTX not found for domain" + " [%s]!\n", preq->domain->name)); + goto done; + }
- ret = sysdb_cache_auth(sysdb, pd->user, - pd->authtok, pd->authtok_size, - pctx->rctx->cdb, false, - &exp_date, &delay_until); + password = talloc_strndup(preq, pd->authtok, pd->authtok_size); + if (!password) { + DEBUG(0, ("Fatal: Out of memory copying password\n")); + goto done; + }
- pam_cache_auth_done(preq, ret, exp_date, delay_until); - return; + ret = sysdb_cache_auth(preq->domain->sysdb, + pd->user, password, + pctx->rctx->cdb, false, + &exp_date, &delay_until); + + pam_cache_auth_done(preq, ret, exp_date, delay_until); + if (password) { + for (i = 0; password[i]; i++) password[i] = 0; + talloc_zfree(password); + } + return; } break; case SSS_PAM_CHAUTHTOK_PRELIM: diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c index 3a07a6495d3aa2d82c54acc9312704cdfd7056af..8808fbf698f9686f6814fdc4a0d690be4f4a3212 100644 --- a/src/tests/sysdb-tests.c +++ b/src/tests/sysdb-tests.c @@ -1492,8 +1492,7 @@ static void cached_authentication_without_expiration(const char *username, return; }
- ret = sysdb_cache_auth(test_ctx->sysdb, data->username, - (const uint8_t *)password, strlen(password), + ret = sysdb_cache_auth(test_ctx->sysdb, data->username, password, test_ctx->confdb, false, &expire_date, &delayed_until);
fail_unless(ret == expected_result, "sysdb_cache_auth request does not " @@ -1552,8 +1551,7 @@ static void cached_authentication_with_expiration(const char *username, data->attrs, SYSDB_MOD_REP); fail_unless(ret == EOK, "Could not modify user %s", data->username);
- ret = sysdb_cache_auth(test_ctx->sysdb, data->username, - (const uint8_t *) password, strlen(password), + ret = sysdb_cache_auth(test_ctx->sysdb, data->username, password, test_ctx->confdb, false, &expire_date, &delayed_until);
fail_unless(ret == expected_result,
This is useful for wiping passwords, as it prevents the compiler from optimizing out a memset to zero before a free() --- src/util/util.c | 9 +++++++++ src/util/util.h | 10 ++++++++++ 2 files changed, 19 insertions(+), 0 deletions(-)
diff --git a/src/util/util.c b/src/util/util.c index b812ef1b118803129caae25247efcbc1194b22f5..061291c04bb581082aa98d79b6b1ec1a1d1090ac 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -634,3 +634,12 @@ remove_ipv6_brackets(char *ipv6addr)
return EOK; } + +void safezero(void *data, size_t size) +{ + volatile uint8_t *p = data; + + while (size--) { + *p++ = 0; + } +} diff --git a/src/util/util.h b/src/util/util.h index d9315aefe0b88965a492f1bc56a6c940ebec5ad5..93791135322a9aeb4ce473c5e255a6e538c57d90 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -535,6 +535,16 @@ sss_escape_ip_address(TALLOC_CTX *mem_ctx, int family, const char *addr); errno_t remove_ipv6_brackets(char *ipv6addr);
+ +/** + * @brief Safely zero a segment of memory, + * prevents the compiler from optimizing out + * + * @param data The address of buffer to wipe + * @param s Size of the buffer + */ +void safezero(void *data, size_t size); + /* from sss_tc_utf8.c */ char * sss_tc_utf8_str_tolower(TALLOC_CTX *mem_ctx, const char *s);
These functions allow handling of auth tokens in a completely opaque way, with clear semantics and accessor fucntions that guarantee consistency, proper access to data and error conditions. --- Makefile.am | 2 + src/util/authtok.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/util/authtok.h | 180 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 377 insertions(+), 0 deletions(-) create mode 100644 src/util/authtok.c create mode 100644 src/util/authtok.h
diff --git a/Makefile.am b/Makefile.am index 3306bbac029bb4cc8d36d9e38a66632753a69c68..2b8bb249c4134fc2b12533e5dda71c8a67ada3ca 100644 --- a/Makefile.am +++ b/Makefile.am @@ -368,6 +368,7 @@ dist_noinst_HEADERS = \ src/util/murmurhash3.h \ src/util/mmap_cache.h \ src/util/atomic_io.h \ + src/util/authtok.h \ src/monitor/monitor.h \ src/monitor/monitor_interfaces.h \ src/responder/common/responder.h \ @@ -506,6 +507,7 @@ libsss_util_la_SOURCES = \ src/util/sss_tc_utf8.c \ src/util/murmurhash3.c \ src/util/atomic_io.c \ + src/util/authtok.c \ src/util/sss_selinux.c \ src/util/domain_info_utils.c \ src/util/util_lock.c diff --git a/src/util/authtok.c b/src/util/authtok.c new file mode 100644 index 0000000000000000000000000000000000000000..1f45953378021e9d30559030326134794965b240 --- /dev/null +++ b/src/util/authtok.c @@ -0,0 +1,195 @@ +/* + SSSD - auth utils + + Copyright (C) Simo Sorce simo@redhat.com 2012 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses/. +*/ + +#include "authtok.h" + +enum sss_authtok_type sss_authtok_get_type(struct sss_auth_token *tok) +{ + return tok->type; +} + +size_t sss_authtok_get_size(struct sss_auth_token *tok) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_PASSWORD: + case SSS_AUTHTOK_TYPE_CCFILE: + return tok->length; + default: + return 0; + } +} + +uint8_t *sss_authtok_get_data(struct sss_auth_token *tok) +{ + return (void *)tok->data; +} + +errno_t sss_authtok_get_password(struct sss_auth_token *tok, + const char **pwd, size_t *len) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_EMPTY: + return ENOENT; + case SSS_AUTHTOK_TYPE_PASSWORD: + *pwd = (const char *)tok->data; + if (len) { + *len = tok->length - 1; + } + return EOK; + default: + return EACCES; + } +} + +errno_t sss_authtok_get_ccfile(struct sss_auth_token *tok, + const char **ccfile, size_t *len) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_EMPTY: + return ENOENT; + case SSS_AUTHTOK_TYPE_CCFILE: + *ccfile = (const char *)tok->data; + if (len) { + *len = tok->length - 1; + } + return EOK; + default: + return EACCES; + } +} + +static errno_t sss_authtok_set_string(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + enum sss_authtok_type type, + const char *context_name, + const char *str, size_t len) +{ + size_t size; + + if (len == 0) { + len = strlen(str); + } else { + while (len > 0 && str[len - 1] == '\0') len--; + } + + if (len == 0) { + /* we do not allow zero length ttyped tokens */ + return EINVAL; + } + + size = len + 1; + + tok->data = talloc_named(mem_ctx, size, context_name); + if (!tok->data) { + return ENOMEM; + } + memcpy(tok->data, str, len); + tok->data[len] = '\0'; + tok->type = type; + tok->length = size; + + return EOK; + +} + +void sss_authtok_set_empty(struct sss_auth_token *tok) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_EMPTY: + return; + case SSS_AUTHTOK_TYPE_PASSWORD: + safezero(tok->data, tok->length); + default: + break; + } + + tok->type = SSS_AUTHTOK_TYPE_EMPTY; + talloc_zfree(tok->data); + tok->length = 0; +} + +errno_t sss_authtok_set_password(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *password, size_t len) +{ + sss_authtok_set_empty(tok); + + return sss_authtok_set_string(mem_ctx, tok, + SSS_AUTHTOK_TYPE_PASSWORD, + "password", password, len); +} + +errno_t sss_authtok_set_ccfile(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *ccfile, size_t len) +{ + sss_authtok_set_empty(tok); + + return sss_authtok_set_string(mem_ctx, tok, + SSS_AUTHTOK_TYPE_CCFILE, + "ccfile", ccfile, len); +} + +errno_t sss_authtok_set(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + enum sss_authtok_type type, + uint8_t *data, size_t len) +{ + switch (type) { + case SSS_AUTHTOK_TYPE_PASSWORD: + return sss_authtok_set_password(mem_ctx, tok, (const char *)data, len); + case SSS_AUTHTOK_TYPE_CCFILE: + return sss_authtok_set_ccfile(mem_ctx, tok, (const char *)data, len); + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + return EOK; + default: + return EINVAL; + } +} + +errno_t sss_authtok_copy(TALLOC_CTX *mem_ctx, + struct sss_auth_token *src, + struct sss_auth_token *dst) +{ + sss_authtok_set_empty(dst); + + if (src->type == SSS_AUTHTOK_TYPE_EMPTY) { + return EOK; + } + + dst->data = talloc_memdup(mem_ctx, src->data, src->length); + if (!dst->data) { + return ENOMEM; + } + dst->length = src->length; + dst->type = src->type; + + return EOK; +} + +void sss_authtok_wipe_password(struct sss_auth_token *tok) +{ + if (tok->type != SSS_AUTHTOK_TYPE_PASSWORD) { + return; + } + + safezero(tok->data, tok->length); +} + diff --git a/src/util/authtok.h b/src/util/authtok.h new file mode 100644 index 0000000000000000000000000000000000000000..c750711ea373506118aab75807dc706c217f6842 --- /dev/null +++ b/src/util/authtok.h @@ -0,0 +1,180 @@ +/* + SSSD - auth utils + + Copyright (C) Simo Sorce simo@redhat.com 2012 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses/. +*/ + +#ifndef __AUTHTOK_H__ +#define __AUTHTOK_H__ + +#include "util/util.h" +#include "sss_client/sss_cli.h" + +/* Auth token structure, + * please never use directly. + * Use ss_authtok_* accesor functions instead + */ +struct sss_auth_token { + enum sss_authtok_type type; + uint8_t *data; + size_t length; +}; + +/** + * @brief Returns the token type + * + * @param tok A pointer to an sss_auth_token + * + * @return A sss_authtok_type (empty, password, ...) + */ +enum sss_authtok_type sss_authtok_get_type(struct sss_auth_token *tok); + +/** + * @brief Returns the token size + * + * @param tok A pointer to an sss_auth_token + * + * @return The current size of the token payload + */ +size_t sss_authtok_get_size(struct sss_auth_token *tok); + +/** + * @brief Get the data buffer + * + * @param tok A pointer to an sss_auth_token + * + * @return A pointer to the token payload + */ +uint8_t *sss_authtok_get_data(struct sss_auth_token *tok); + +/** + * @brief Returns a const string if the auth token is of type + SSS_AUTHTOK_TYPE_PASSWORD, otherwise it returns an error + * + * @param tok A pointer to an sss_auth_token + * @param pwd A pointer to a const char *, that will point to a null + * terminated string + * @param len The length of the password string + * + * @return EOK on success + * ENOENT if the token is empty + * EACCESS if the token is not a password token + */ +errno_t sss_authtok_get_password(struct sss_auth_token *tok, + const char **pwd, size_t *len); + +/** + * @brief Set a password into a an auth token, replacing any previous data + * + * @param mem_ctx A memory context use to allocate the internal data + * @param tok A pointer to a sss_auth_token structure to change + * @param password A string + * @param len The length of the string or, if 0 is passed, + * then strlen(password) will be used internally. + * + * @return EOK on success + * ENOMEM on error + */ +errno_t sss_authtok_set_password(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *password, size_t len); + +/** + * @brief Returns a const string if the auth token is of type + SSS_AUTHTOK_TYPE_CCFILE, otherwise it returns an error + * + * @param tok A pointer to an sss_auth_token + * @param ccfile A pointer to a const char *, that will point to a null + * terminated string + * @param len The length of the string + * + * @return EOK on success + * ENOENT if the token is empty + * EACCESS if the token is not a password token + */ +errno_t sss_authtok_get_ccfile(struct sss_auth_token *tok, + const char **ccfile, size_t *len); + +/** + * @brief Set a cc file name into a an auth token, replacing any previous data + * + * @param mem_ctx A memory context use to allocate the internal data + * @param tok A pointer to a sss_auth_token structure to change + * @param ccfile A null terminated string + * @param len The length of the string + * + * @return EOK on success + * ENOMEM on error + */ +errno_t sss_authtok_set_ccfile(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *ccfile, size_t len); + +/** + * @brief Resets an auth token to the empty status + * + * @param tok A pointer to a sss_auth_token structure to reset + * + * NOTE: This function uses safezero() on the payload if the type + * is SSS_AUTHTOK_TYPE_PASSWORD + */ +void sss_authtok_set_empty(struct sss_auth_token *tok); + +/** + * @brief Set an auth token by type, replacing any previous data + * + * @param mem_ctx A memory context use to allocate the internal data + * @param tok A pointer to a sss_auth_token structure to change + * @param type A valid authtok type + * @param ccfile A data pointer + * @param len The length of the data + * + * @return EOK on success + * ENOMEM or EINVAL on error + */ +errno_t sss_authtok_set(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + enum sss_authtok_type type, + uint8_t *data, size_t len); + +/** + * @brief Copy an auth token from source to destination + * + * @param mem_ctx The memory context to use for allocations on dst + * @param src The source auth token + * @param dst The destination auth token + * + * @return EOK on success + * ENOMEM on error + */ +errno_t sss_authtok_copy(TALLOC_CTX *mem_ctx, + struct sss_auth_token *src, + struct sss_auth_token *dst); + +/** + * @brief Uses safezero to wipe the password from memory if the + * authtoken contains a password, otherwise does nothing. + * + * @param tok A pointer to a sss_auth_token structure to change + * + * NOTE: This function should only be used in destructors or similar + * functions where freing the actual string is unsafe and where it can + * be guaranteed that the auth token will not be used anymore. + * Use sss_authtok_set_empty() in normal circumstances. + */ +void sss_authtok_wipe_password(struct sss_auth_token *tok); + +#endif /* __AUTHTOK_H__ */
Use the new authtok abstraction and interfaces throught the code. --- Makefile.am | 2 + src/db/sysdb_ops.c | 1 - src/providers/data_provider.h | 9 +- src/providers/dp_auth_util.c | 76 +++++++---- src/providers/dp_pam_data_util.c | 113 ++++++++------- src/providers/ipa/ipa_auth.c | 6 +- src/providers/krb5/krb5_auth.c | 55 +++----- src/providers/krb5/krb5_child.c | 148 ++++++++++---------- src/providers/krb5/krb5_child_handler.c | 59 +++++++-- .../krb5/krb5_delayed_online_authentication.c | 50 +++++--- src/providers/krb5/krb5_renew_tgt.c | 18 +-- src/providers/ldap/ldap_auth.c | 90 +++++------- src/providers/ldap/sdap_async.c | 4 +- src/providers/ldap/sdap_async.h | 7 +- src/providers/ldap/sdap_async_connection.c | 88 +++++++----- src/providers/proxy/proxy.h | 7 +- src/providers/proxy/proxy_auth.c | 14 +- src/providers/proxy/proxy_child.c | 51 ++++--- src/responder/pam/pam_LOCAL_domain.c | 52 +++----- src/responder/pam/pamsrv_cmd.c | 134 ++++++++++-------- src/tests/krb5_child-test.c | 13 +- 21 files changed, 529 insertions(+), 468 deletions(-)
diff --git a/Makefile.am b/Makefile.am index 2b8bb249c4134fc2b12533e5dda71c8a67ada3ca..cf8ea72afa45c47ea40090aa314b28c0867939ba 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1445,6 +1445,7 @@ krb5_child_SOURCES = \ src/util/user_info_msg.c \ src/util/sss_krb5.c \ src/util/atomic_io.c \ + src/util/authtok.c \ src/util/util.c \ src/util/signal.c \ src/sss_client/common.c @@ -1466,6 +1467,7 @@ ldap_child_SOURCES = \ src/providers/ldap/ldap_child.c \ src/util/sss_krb5.c \ src/util/atomic_io.c \ + src/util/authtok.c \ src/util/util.c \ src/util/signal.c ldap_child_CFLAGS = \ diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c index 9f476e98ef0c09f39659d52b927224a20e42db07..8349115ce9e34a894b8f115807bc666a25447b8c 100644 --- a/src/db/sysdb_ops.c +++ b/src/db/sysdb_ops.c @@ -2677,7 +2677,6 @@ int sysdb_cache_auth(struct sysdb_ctx *sysdb, time_t expire_date = -1; time_t delayed_until = -1; int ret; - int i;
if (name == NULL || *name == '\0') { DEBUG(1, ("Missing user name.\n")); diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h index bb944509da9f1dc89216266cf62c57fb4127fd57..b370aa51dbe4015a26512a0f003defdb6851bf63 100644 --- a/src/providers/data_provider.h +++ b/src/providers/data_provider.h @@ -41,6 +41,7 @@ #include "sbus/sssd_dbus.h" #include "sbus/sbus_client.h" #include "sss_client/sss_cli.h" +#include "util/authtok.h"
#define DATA_PROVIDER_VERSION 0x0001 #define DATA_PROVIDER_PIPE "private/sbus-dp" @@ -162,18 +163,14 @@ struct response_data {
struct pam_data { int cmd; - uint32_t authtok_type; - uint32_t authtok_size; - uint32_t newauthtok_type; - uint32_t newauthtok_size; char *domain; char *user; char *service; char *tty; char *ruser; char *rhost; - uint8_t *authtok; - uint8_t *newauthtok; + struct sss_auth_token authtok; + struct sss_auth_token newauthtok; uint32_t cli_pid;
int pam_status; diff --git a/src/providers/dp_auth_util.c b/src/providers/dp_auth_util.c index 9a67564b78e558642f4116528d210251a0d9b5fd..54f0ee8ed6f1d537410a91f93e55316fc9b89886 100644 --- a/src/providers/dp_auth_util.c +++ b/src/providers/dp_auth_util.c @@ -24,30 +24,43 @@ bool dp_pack_pam_request(DBusMessage *msg, struct pam_data *pd) { dbus_bool_t db_ret; + const char *service; + const char *tty; + const char *ruser; + const char *rhost; + uint32_t authtok_type; + uint32_t authtok_length; + uint8_t *authtok_data; + uint32_t new_authtok_type; + uint32_t new_authtok_length; + uint8_t *new_authtok_data;
if (pd->user == NULL) return false; - if (pd->service == NULL) pd->service = talloc_strdup(pd, ""); - if (pd->tty == NULL) pd->tty = talloc_strdup(pd, ""); - if (pd->ruser == NULL) pd->ruser = talloc_strdup(pd, ""); - if (pd->rhost == NULL) pd->rhost = talloc_strdup(pd, ""); - + service = pd->service ? pd->service : ""; + tty = pd->tty ? pd->tty : ""; + ruser = pd->ruser ? pd->ruser : ""; + rhost = pd->rhost ? pd->rhost : ""; + authtok_type = (uint32_t)sss_authtok_get_type(&pd->authtok); + authtok_data = sss_authtok_get_data(&pd->authtok); + authtok_length = sss_authtok_get_size(&pd->authtok); + new_authtok_type = (uint32_t)sss_authtok_get_type(&pd->newauthtok); + new_authtok_data = sss_authtok_get_data(&pd->newauthtok); + new_authtok_length = sss_authtok_get_size(&pd->newauthtok);
db_ret = dbus_message_append_args(msg, DBUS_TYPE_INT32, &(pd->cmd), DBUS_TYPE_STRING, &(pd->user), DBUS_TYPE_STRING, &(pd->domain), - DBUS_TYPE_STRING, &(pd->service), - DBUS_TYPE_STRING, &(pd->tty), - DBUS_TYPE_STRING, &(pd->ruser), - DBUS_TYPE_STRING, &(pd->rhost), - DBUS_TYPE_UINT32, &(pd->authtok_type), + DBUS_TYPE_STRING, &service, + DBUS_TYPE_STRING, &tty, + DBUS_TYPE_STRING, &ruser, + DBUS_TYPE_STRING, &rhost, + DBUS_TYPE_UINT32, &authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd->authtok), - (pd->authtok_size), - DBUS_TYPE_UINT32, &(pd->newauthtok_type), + &authtok_data, authtok_length, + DBUS_TYPE_UINT32, &new_authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd->newauthtok), - pd->newauthtok_size, + &new_authtok_data, new_authtok_length, DBUS_TYPE_INT32, &(pd->priv), DBUS_TYPE_UINT32, &(pd->cli_pid), DBUS_TYPE_INVALID); @@ -61,6 +74,12 @@ bool dp_unpack_pam_request(DBusMessage *msg, TALLOC_CTX *mem_ctx, dbus_bool_t db_ret; int ret; struct pam_data pd; + uint32_t authtok_type; + uint32_t authtok_length; + uint8_t *authtok_data; + uint32_t new_authtok_type; + uint32_t new_authtok_length; + uint8_t *new_authtok_data;
memset(&pd, 0, sizeof(pd));
@@ -72,14 +91,12 @@ bool dp_unpack_pam_request(DBusMessage *msg, TALLOC_CTX *mem_ctx, DBUS_TYPE_STRING, &(pd.tty), DBUS_TYPE_STRING, &(pd.ruser), DBUS_TYPE_STRING, &(pd.rhost), - DBUS_TYPE_UINT32, &(pd.authtok_type), + DBUS_TYPE_UINT32, &authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd.authtok), - &(pd.authtok_size), - DBUS_TYPE_UINT32, &(pd.newauthtok_type), + &authtok_data, &authtok_length, + DBUS_TYPE_UINT32, &new_authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd.newauthtok), - &(pd.newauthtok_size), + &new_authtok_data, &new_authtok_length, DBUS_TYPE_INT32, &(pd.priv), DBUS_TYPE_UINT32, &(pd.cli_pid), DBUS_TYPE_INVALID); @@ -95,14 +112,17 @@ bool dp_unpack_pam_request(DBusMessage *msg, TALLOC_CTX *mem_ctx, return false; }
- if (pd.authtok_size != 0 && pd.authtok != NULL) { - memset(pd.authtok, 0, pd.authtok_size); - pd.authtok_size = 0; + ret = sss_authtok_set(*new_pd, &((*new_pd)->authtok), authtok_type, + authtok_data, authtok_length); + if (ret) { + DEBUG(1, ("Failed to set auth token: %d [%s]\n", ret, strerror(ret))); + return false; } - - if (pd.newauthtok_size != 0 && pd.newauthtok != NULL) { - memset(pd.newauthtok, 0, pd.newauthtok_size); - pd.newauthtok_size = 0; + ret = sss_authtok_set(*new_pd, &((*new_pd)->newauthtok), new_authtok_type, + new_authtok_data, new_authtok_length); + if (ret) { + DEBUG(1, ("Failed to set auth token: %d [%s]\n", ret, strerror(ret))); + return false; }
return true; diff --git a/src/providers/dp_pam_data_util.c b/src/providers/dp_pam_data_util.c index 889c47f00bfb49effab982ed40454b5120b84bf6..64f0d69bd0e8ebc28df958c393b40afcb5e18c31 100644 --- a/src/providers/dp_pam_data_util.c +++ b/src/providers/dp_pam_data_util.c @@ -25,26 +25,6 @@ #include "providers/data_provider.h"
-#define PD_STR_COPY(el) do { \ - if (old_pd->el != NULL) { \ - pd->el = talloc_strdup(pd, old_pd->el); \ - if (pd->el == NULL) { \ - DEBUG(1, ("talloc_strdup failed.\n")); \ - goto failed; \ - } \ - } \ -} while(0) - -#define PD_MEM_COPY(el, size) do { \ - if (old_pd->el != NULL) { \ - pd->el = talloc_memdup(pd, old_pd->el, (size)); \ - if (pd->el == NULL) { \ - DEBUG(1, ("talloc_memdup failed.\n")); \ - goto failed; \ - } \ - } \ -} while(0) - #define PAM_SAFE_ITEM(item) item ? item : "not set"
static const char *pamcmd2str(int cmd) { @@ -72,17 +52,11 @@ int pam_data_destructor(void *ptr) { struct pam_data *pd = talloc_get_type(ptr, struct pam_data);
- if (pd->authtok_size != 0 && pd->authtok != NULL) { - memset(pd->authtok, 0, pd->authtok_size); - pd->authtok_size = 0; - } + /* make sure to wipe any password from memory before freeing */ + sss_authtok_wipe_password(&pd->authtok); + sss_authtok_wipe_password(&pd->newauthtok);
- if (pd->newauthtok_size != 0 && pd->newauthtok != NULL) { - memset(pd->newauthtok, 0, pd->newauthtok_size); - pd->newauthtok_size = 0; - } - - return EOK; + return 0; }
struct pam_data *create_pam_data(TALLOC_CTX *mem_ctx) @@ -100,41 +74,72 @@ struct pam_data *create_pam_data(TALLOC_CTX *mem_ctx) return pd; }
-errno_t copy_pam_data(TALLOC_CTX *mem_ctx, struct pam_data *old_pd, - struct pam_data **new_pd) +errno_t copy_pam_data(TALLOC_CTX *mem_ctx, struct pam_data *src, + struct pam_data **dst) { struct pam_data *pd = NULL; + errno_t ret;
pd = create_pam_data(mem_ctx); if (pd == NULL) { - DEBUG(1, ("create_pam_data failed.\n")); - return ENOMEM; + ret = ENOMEM; + goto failed; }
- pd->cmd = old_pd->cmd; - pd->authtok_type = old_pd->authtok_type; - pd->authtok_size = old_pd->authtok_size; - pd->newauthtok_type = old_pd->newauthtok_type; - pd->newauthtok_size = old_pd->newauthtok_size; - pd->priv = old_pd->priv; + pd->cmd = src->cmd; + pd->priv = src->priv;
- PD_STR_COPY(domain); - PD_STR_COPY(user); - PD_STR_COPY(service); - PD_STR_COPY(tty); - PD_STR_COPY(ruser); - PD_STR_COPY(rhost); - PD_MEM_COPY(authtok, old_pd->authtok_size); - PD_MEM_COPY(newauthtok, old_pd->newauthtok_size); - pd->cli_pid = old_pd->cli_pid; + pd->domain = talloc_strdup(pd, src->domain); + if (pd->domain == NULL && src->domain != NULL) { + ret = ENOMEM; + goto failed; + } + pd->user = talloc_strdup(pd, src->user); + if (pd->user == NULL && src->user != NULL) { + ret = ENOMEM; + goto failed; + } + pd->service = talloc_strdup(pd, src->service); + if (pd->service == NULL && src->service != NULL) { + ret = ENOMEM; + goto failed; + } + pd->tty = talloc_strdup(pd, src->tty); + if (pd->tty == NULL && src->tty != NULL) { + ret = ENOMEM; + goto failed; + } + pd->ruser = talloc_strdup(pd, src->ruser); + if (pd->ruser == NULL && src->ruser != NULL) { + ret = ENOMEM; + goto failed; + } + pd->rhost = talloc_strdup(pd, src->rhost); + if (pd->rhost == NULL && src->rhost != NULL) { + ret = ENOMEM; + goto failed; + } + + pd->cli_pid = src->cli_pid; + + ret = sss_authtok_copy(pd, &src->authtok, &pd->authtok); + if (ret) { + goto failed; + } + + ret = sss_authtok_copy(pd, &src->newauthtok, &pd->newauthtok); + if (ret) { + goto failed; + }
- *new_pd = pd; + *dst = pd;
return EOK;
failed: talloc_free(pd); - return ENOMEM; + DEBUG(1, ("copy_pam_data failed: (%d) %s.\n", ret, strerror(ret))); + return ret; }
void pam_print_data(int l, struct pam_data *pd) @@ -146,10 +151,8 @@ void pam_print_data(int l, struct pam_data *pd) DEBUG(l, ("tty: %s\n", PAM_SAFE_ITEM(pd->tty))); DEBUG(l, ("ruser: %s\n", PAM_SAFE_ITEM(pd->ruser))); DEBUG(l, ("rhost: %s\n", PAM_SAFE_ITEM(pd->rhost))); - DEBUG(l, ("authtok type: %d\n", pd->authtok_type)); - DEBUG(l, ("authtok size: %d\n", pd->authtok_size)); - DEBUG(l, ("newauthtok type: %d\n", pd->newauthtok_type)); - DEBUG(l, ("newauthtok size: %d\n", pd->newauthtok_size)); + DEBUG(l, ("authtok type: %d\n", sss_authtok_get_type(&pd->authtok))); + DEBUG(l, ("newauthtok type: %d\n", sss_authtok_get_type(&pd->newauthtok))); DEBUG(l, ("priv: %d\n", pd->priv)); DEBUG(l, ("cli_pid: %d\n", pd->cli_pid)); } diff --git a/src/providers/ipa/ipa_auth.c b/src/providers/ipa/ipa_auth.c index eb62f0295cc0dc36daad9d4147556d993c7f1509..ee15afa5c83c0c68d19e169649ae6958a1553bd1 100644 --- a/src/providers/ipa/ipa_auth.c +++ b/src/providers/ipa/ipa_auth.c @@ -332,7 +332,6 @@ static void ipa_migration_flag_connect_done(struct tevent_req *req) const char **attrs; struct ldb_message *user_msg; const char *dn; - struct dp_opt_blob password; int dp_err = DP_ERR_FATAL; int ret;
@@ -374,11 +373,8 @@ static void ipa_migration_flag_connect_done(struct tevent_req *req) goto done; }
- password.data = state->pd->authtok; - password.length = state->pd->authtok_size; - req = sdap_auth_send(state, state->ev, state->sh, NULL, NULL, dn, - "password", password); + &state->pd->authtok); if (req == NULL) { DEBUG(SSSDBG_OP_FAILURE, ("sdap_auth_send failed.\n")); goto done; diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c index 5553abd76c7f0e1717a9cf31c76bda0370174f40..604c78d95984ddd43de2e23e464c1adf1a7bf52f 100644 --- a/src/providers/krb5/krb5_auth.c +++ b/src/providers/krb5/krb5_auth.c @@ -277,12 +277,12 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, struct pam_data *pd, uid_t uid, int *pam_status, int *dp_err) { - char *password = NULL; + const char *password = NULL; errno_t ret;
- password = talloc_strndup(state, pd->authtok, pd->authtok_size); - if (!password) { - DEBUG(0, ("Out of memory copying password\n")); + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + if (ret != EOK) { + DEBUG(0, ("Failed to get password [%d] %s\n", ret, strerror(ret))); *pam_status = PAM_SYSTEM_ERR; *dp_err = DP_ERR_OK; return; @@ -293,7 +293,7 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, DEBUG(1, ("Offline authentication failed\n")); *pam_status = PAM_SYSTEM_ERR; *dp_err = DP_ERR_OK; - goto done; + return; }
ret = add_user_to_delayed_online_authentication(krb5_ctx, pd, uid); @@ -303,12 +303,6 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, } *pam_status = PAM_AUTHINFO_UNAVAIL; *dp_err = DP_ERR_OFFLINE; - -done: - if (password) { - for (i = 0; password[i]; i++) password[i] = 0; - talloc_zfree(password); - } }
static errno_t krb5_auth_prepare_ccache_file(struct krb5child_req *kr, @@ -387,16 +381,9 @@ static errno_t krb5_auth_prepare_ccache_file(struct krb5child_req *kr,
static void krb5_auth_store_creds(struct sysdb_ctx *sysdb, struct pam_data *pd) { - TALLOC_CTX *tmp_ctx; char *password = NULL; int ret = EOK;
- tmp_ctx = talloc_new(NULL); - if (!tmp_ctx) { - DEBUG(0, ("Out of memory when trying to store credentials\n")); - return; - } - switch(pd->cmd) { case SSS_CMD_RENEW: /* The authtok is set to the credential cache @@ -406,23 +393,21 @@ static void krb5_auth_store_creds(struct sysdb_ctx *sysdb, struct pam_data *pd) break; case SSS_PAM_AUTHENTICATE: case SSS_PAM_CHAUTHTOK_PRELIM: - password = talloc_size(tmp_ctx, pd->authtok_size + 1); - if (password != NULL) { - memcpy(password, pd->authtok, pd->authtok_size); - password[pd->authtok_size] = '\0'; - } + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); break; case SSS_PAM_CHAUTHTOK: - password = talloc_size(tmp_ctx, pd->newauthtok_size + 1); - if (password != NULL) { - memcpy(password, pd->newauthtok, pd->newauthtok_size); - password[pd->newauthtok_size] = '\0'; - } + ret = sss_authtok_get_password(&pd->newauthtok, &password, NULL); break; default: DEBUG(0, ("unsupported PAM command [%d].\n", pd->cmd)); }
+ if (ret != EOK) { + DEBUG(0, ("Failed to get password [%d] %s\n", ret, strerror(ret))); + /* password caching failures are not fatal errors */ + return; + } + if (password == NULL) { if (pd->cmd != SSS_CMD_RENEW) { DEBUG(0, ("password not available, offline auth may not work.\n")); @@ -431,16 +416,12 @@ static void krb5_auth_store_creds(struct sysdb_ctx *sysdb, struct pam_data *pd) return; }
- talloc_set_destructor((TALLOC_CTX *)password, password_destructor); - ret = sysdb_cache_password(sysdb, pd->user, password); if (ret) { DEBUG(2, ("Failed to cache password, offline auth may not work." " (%d)[%s]!?\n", ret, strerror(ret))); /* password caching failures are not fatal errors */ } - - talloc_zfree(tmp_ctx); }
/* krb5_auth request */ @@ -505,9 +486,17 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx, case SSS_PAM_AUTHENTICATE: case SSS_CMD_RENEW: case SSS_PAM_CHAUTHTOK: + if (sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { + DEBUG(1, ("Missing authtok for user [%s].\n", pd->user)); + state->pam_status = PAM_SYSTEM_ERR; + state->dp_err = DP_ERR_FATAL; + ret = EINVAL; + goto done; + } break; case SSS_PAM_CHAUTHTOK_PRELIM: - if (pd->priv == 1 && pd->authtok_size == 0) { + if (pd->priv == 1 && + sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { DEBUG(4, ("Password reset by root is not supported.\n")); state->pam_status = PAM_PERM_DENIED; state->dp_err = DP_ERR_OK; diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c index e7776248b8f6284f86f8fc11b00cd4b122af13df..af35d5e5d301fbca18e100ea5f29eb2aa1fc0850 100644 --- a/src/providers/krb5/krb5_child.c +++ b/src/providers/krb5/krb5_child.c @@ -1014,7 +1014,7 @@ done: }
static krb5_error_code get_and_save_tgt(struct krb5_req *kr, - char *password) + const char *password) { krb5_error_code kerr = 0; int ret; @@ -1035,7 +1035,8 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr, DEBUG(SSSDBG_TRACE_FUNC, ("Attempting kinit for realm [%s]\n",realm_name)); kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - password, sss_krb5_prompter, kr, 0, + discard_const(password), + sss_krb5_prompter, kr, 0, NULL, kr->options); if (kerr != 0) { KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); @@ -1130,8 +1131,8 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) { int ret; krb5_error_code kerr = 0; - char *pass_str = NULL; - char *newpass_str = NULL; + const char *password = NULL; + const char *newpassword = NULL; int pam_status = PAM_SYSTEM_ERR; int result_code = -1; krb5_data result_code_string; @@ -1146,20 +1147,15 @@ static errno_t changepw_child(int fd, struct krb5_req *kr)
DEBUG(SSSDBG_TRACE_LIBS, ("Password change operation\n"));
- if (kr->pd->authtok_type != SSS_AUTHTOK_TYPE_PASSWORD) { + ret = sss_authtok_get_password(&kr->pd->authtok, &password, NULL); + if (ret != EOK) { + DEBUG(1, ("Failed to fetch current password [%d] %s.\n", + ret, strerror(ret))); pam_status = PAM_CRED_INSUFFICIENT; kerr = KRB5KRB_ERR_GENERIC; goto sendresponse; }
- pass_str = talloc_strndup(kr, (const char *) kr->pd->authtok, - kr->pd->authtok_size); - if (pass_str == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - kerr = KRB5KRB_ERR_GENERIC; - goto sendresponse; - } - changepw_princ = talloc_asprintf(kr, "%s@%s", SSSD_KRB5_CHANGEPW_PRINCIPAL, kr->krb5_ctx->realm); if (changepw_princ == NULL) { @@ -1180,7 +1176,8 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) DEBUG(SSSDBG_TRACE_FUNC, ("Attempting kinit for realm [%s]\n",realm_name)); kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - pass_str, prompter, kr, 0, + discard_const(password), + prompter, kr, 0, changepw_princ, kr->options); if (kerr != 0) { @@ -1188,9 +1185,7 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) goto sendresponse; }
- memset(pass_str, 0, kr->pd->authtok_size); - talloc_zfree(pass_str); - memset(kr->pd->authtok, 0, kr->pd->authtok_size); + sss_authtok_set_empty(&kr->pd->authtok);
if (kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) { DEBUG(SSSDBG_TRACE_LIBS, @@ -1201,17 +1196,18 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) goto sendresponse; }
- newpass_str = talloc_strndup(kr, (const char *) kr->pd->newauthtok, - kr->pd->newauthtok_size); - if (newpass_str == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); + ret = sss_authtok_get_password(&kr->pd->newauthtok, &newpassword, NULL); + if (ret != EOK) { + DEBUG(1, ("Failed to fetch new password [%d] %s.\n", + ret, strerror(ret))); kerr = KRB5KRB_ERR_GENERIC; goto sendresponse; }
memset(&result_code_string, 0, sizeof(krb5_data)); memset(&result_string, 0, sizeof(krb5_data)); - kerr = krb5_change_password(kr->ctx, kr->creds, newpass_str, &result_code, + kerr = krb5_change_password(kr->ctx, kr->creds, + discard_const(newpassword), &result_code, &result_code_string, &result_string);
if (kerr == KRB5_KDC_UNREACH) { @@ -1267,10 +1263,9 @@ static errno_t changepw_child(int fd, struct krb5_req *kr)
krb5_free_cred_contents(kr->ctx, kr->creds);
- kerr = get_and_save_tgt(kr, newpass_str); - memset(newpass_str, 0, kr->pd->newauthtok_size); - talloc_zfree(newpass_str); - memset(kr->pd->newauthtok, 0, kr->pd->newauthtok_size); + kerr = get_and_save_tgt(kr, newpassword); + + sss_authtok_set_empty(&kr->pd->newauthtok);
pam_status = kerr_to_status(kerr);
@@ -1287,27 +1282,20 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) { int ret; krb5_error_code kerr = 0; - char *pass_str = NULL; + const char *password = NULL; char *changepw_princ = NULL; int pam_status = PAM_SYSTEM_ERR;
DEBUG(SSSDBG_TRACE_LIBS, ("Attempting to get a TGT\n"));
- if (kr->pd->authtok_type != SSS_AUTHTOK_TYPE_PASSWORD) { + ret = sss_authtok_get_password(&kr->pd->authtok, &password, NULL); + if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Unknown authtok type\n")); pam_status = PAM_CRED_INSUFFICIENT; kerr = KRB5KRB_ERR_GENERIC; goto sendresponse; }
- pass_str = talloc_strndup(kr, (const char *) kr->pd->authtok, - kr->pd->authtok_size); - if (pass_str == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - kerr = KRB5KRB_ERR_GENERIC; - goto sendresponse; - } - changepw_princ = talloc_asprintf(kr, "%s@%s", SSSD_KRB5_CHANGEPW_PRINCIPAL, kr->krb5_ctx->realm); if (changepw_princ == NULL) { @@ -1318,7 +1306,7 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) DEBUG(SSSDBG_FUNC_DATA, ("Created a changepw principal [%s]\n", changepw_princ));
- kerr = get_and_save_tgt(kr, pass_str); + kerr = get_and_save_tgt(kr, password);
/* If the password is expired the KDC will always return KRB5KDC_ERR_KEY_EXP regardless if the supplied password is correct or @@ -1334,7 +1322,8 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) DEBUG(1, ("Failed to unset expire callback, continue ...\n")); } kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - pass_str, sss_krb5_prompter, kr, 0, + discard_const(password), + sss_krb5_prompter, kr, 0, changepw_princ, kr->options); krb5_free_cred_contents(kr->ctx, kr->creds); @@ -1343,9 +1332,7 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) } }
- memset(pass_str, 0, kr->pd->authtok_size); - talloc_zfree(pass_str); - memset(kr->pd->authtok, 0, kr->pd->authtok_size); + sss_authtok_set_empty(&kr->pd->authtok);
pam_status = kerr_to_status(kerr);
@@ -1400,25 +1387,20 @@ static errno_t renew_tgt_child(int fd, struct krb5_req *kr) int ret; int status = PAM_AUTHTOK_ERR; int kerr; - char *ccname; + const char *ccname; krb5_ccache ccache = NULL;
DEBUG(SSSDBG_TRACE_LIBS, ("Renewing a ticket\n"));
- if (kr->pd->authtok_type != SSS_AUTHTOK_TYPE_CCFILE) { - DEBUG(1, ("Unsupported authtok type for TGT renewal [%d].\n", - kr->pd->authtok_type)); + ret = sss_authtok_get_ccfile(&kr->pd->authtok, &ccname, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + ("Unsupported authtok type for TGT renewal [%d].\n", + sss_authtok_get_type(&kr->pd->authtok))); kerr = EINVAL; goto done; }
- ccname = talloc_strndup(kr, (char *) kr->pd->authtok, kr->pd->authtok_size); - if (ccname == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - kerr = ENOMEM; - goto done; - } - kerr = krb5_cc_resolve(kr->ctx, ccname, &ccache); if (kerr != 0) { KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); @@ -1511,6 +1493,38 @@ static errno_t create_empty_ccache(int fd, struct krb5_req *kr) return ret; }
+static errno_t unpack_authtok(TALLOC_CTX *mem_ctx, struct sss_auth_token *tok, + uint8_t *buf, size_t size, size_t *p) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + errno_t ret = EOK; + + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, buf + *p, size, p); + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_length, buf + *p, size, p); + if ((*p + auth_token_length) > size) { + return EINVAL; + } + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_set_password(mem_ctx, tok, (char *)(buf + *p), 0); + break; + case SSS_AUTHTOK_TYPE_CCFILE: + ret = sss_authtok_set_ccfile(mem_ctx, tok, (char *)(buf + *p), 0); + break; + default: + return EINVAL; + } + + if (ret == EOK) { + *p += auth_token_length; + } + return ret; +} + static errno_t unpack_buffer(uint8_t *buf, size_t size, struct pam_data *pd, struct krb5_req *kr, uint32_t *offline) { @@ -1518,6 +1532,7 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size, struct pam_data *pd, uint32_t len; uint32_t validate; uint32_t different_realm; + errno_t ret;
DEBUG(SSSDBG_TRACE_LIBS, ("total buffer size: [%d]\n", size));
@@ -1558,35 +1573,26 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size, struct pam_data *pd, if (kr->keytab == NULL) return ENOMEM; p += len;
- SAFEALIGN_COPY_UINT32_CHECK(&pd->authtok_type, buf + p, size, &p); - SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p); - if ((p + len) > size) return EINVAL; - pd->authtok = (uint8_t *)talloc_strndup(pd, (char *)(buf + p), len); - if (pd->authtok == NULL) return ENOMEM; - pd->authtok_size = len + 1; - p += len; + ret = unpack_authtok(pd, &pd->authtok, buf, size, &p); + if (ret) { + return ret; + }
DEBUG(SSSDBG_CONF_SETTINGS, ("ccname: [%s] keytab: [%s]\n", kr->ccname, kr->keytab)); } else { kr->ccname = NULL; kr->keytab = NULL; - pd->authtok = NULL; - pd->authtok_size = 0; + sss_authtok_set_empty(&pd->authtok); }
if (pd->cmd == SSS_PAM_CHAUTHTOK) { - SAFEALIGN_COPY_UINT32_CHECK(&pd->newauthtok_type, buf + p, size, &p); - SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p); - - if ((p + len) > size) return EINVAL; - pd->newauthtok = (uint8_t *)talloc_strndup(pd, (char *)(buf + p), len); - if (pd->newauthtok == NULL) return ENOMEM; - pd->newauthtok_size = len + 1; - p += len; + ret = unpack_authtok(pd, &pd->newauthtok, buf, size, &p); + if (ret) { + return ret; + } } else { - pd->newauthtok = NULL; - pd->newauthtok_size = 0; + sss_authtok_set_empty(&pd->newauthtok); }
if (pd->cmd == SSS_PAM_ACCT_MGMT) { diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c index e792db3f7a6ebe7857b1ec699bc37d52ae3cad5d..5adbcf700ebf02a2aa524af3cecab51e543b4986 100644 --- a/src/providers/krb5/krb5_child_handler.c +++ b/src/providers/krb5/krb5_child_handler.c @@ -85,6 +85,43 @@ static int child_io_destructor(void *ptr) return EOK; }
+static errno_t pack_authtok(struct io_buffer *buf, size_t *rp, + struct sss_auth_token *tok) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + const char *data; + size_t len; + errno_t ret = EOK; + + auth_token_type = sss_authtok_get_type(tok); + + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + auth_token_length = 0; + data = ""; + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_get_password(tok, &data, &len); + auth_token_length = len + 1; + break; + case SSS_AUTHTOK_TYPE_CCFILE: + ret = sss_authtok_get_password(tok, &data, &len); + auth_token_length = len + 1; + break; + default: + ret = EINVAL; + } + + if (ret == EOK) { + SAFEALIGN_COPY_UINT32(&buf->data[*rp], &auth_token_type, rp); + SAFEALIGN_COPY_UINT32(&buf->data[*rp], &auth_token_length, rp); + safealign_memcpy(&buf->data[*rp], data, auth_token_length, rp); + } + + return ret; +} + static errno_t create_send_buffer(struct krb5child_req *kr, struct io_buffer **io_buf) { @@ -94,6 +131,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr, uint32_t validate; uint32_t different_realm; size_t username_len = 0; + errno_t ret;
keytab = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_KEYTAB); if (keytab == NULL) { @@ -117,11 +155,12 @@ static errno_t create_send_buffer(struct krb5child_req *kr, kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM || kr->pd->cmd == SSS_PAM_CHAUTHTOK) { buf->size += 4*sizeof(uint32_t) + strlen(kr->ccname) + strlen(keytab) + - kr->pd->authtok_size; + sss_authtok_get_size(&kr->pd->authtok); }
if (kr->pd->cmd == SSS_PAM_CHAUTHTOK) { - buf->size += 2*sizeof(uint32_t) + kr->pd->newauthtok_size; + buf->size += 2*sizeof(uint32_t) + + sss_authtok_get_size(&kr->pd->newauthtok); }
if (kr->pd->cmd == SSS_PAM_ACCT_MGMT) { @@ -157,17 +196,17 @@ static errno_t create_send_buffer(struct krb5child_req *kr, SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(keytab), &rp); safealign_memcpy(&buf->data[rp], keytab, strlen(keytab), &rp);
- SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->authtok_type, &rp); - SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->authtok_size, &rp); - safealign_memcpy(&buf->data[rp], kr->pd->authtok, - kr->pd->authtok_size, &rp); + ret = pack_authtok(buf, &rp, &kr->pd->authtok); + if (ret) { + return ret; + } }
if (kr->pd->cmd == SSS_PAM_CHAUTHTOK) { - SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->newauthtok_type, &rp); - SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->newauthtok_size, &rp); - safealign_memcpy(&buf->data[rp], kr->pd->newauthtok, - kr->pd->newauthtok_size, &rp); + ret = pack_authtok(buf, &rp, &kr->pd->newauthtok); + if (ret) { + return ret; + } }
if (kr->pd->cmd == SSS_PAM_ACCT_MGMT) { diff --git a/src/providers/krb5/krb5_delayed_online_authentication.c b/src/providers/krb5/krb5_delayed_online_authentication.c index d5dea3bb4c7661f45b6bea83cf803c7d681062cc..f95fa634c34ebee37bffb785abe4ef5b35318a82 100644 --- a/src/providers/krb5/krb5_delayed_online_authentication.c +++ b/src/providers/krb5/krb5_delayed_online_authentication.c @@ -71,27 +71,29 @@ static void authenticate_user(struct tevent_context *ev,
DEBUG_PAM_DATA(9, pd);
- if (pd->authtok == NULL || pd->authtok_size == 0) { - DEBUG(1, ("Missing authtok for user [%s].\n", pd->user)); - return; - } - #ifdef USE_KEYRING + char *password; long keysize; long keyrevoke; - int ret; - keysize = keyctl_read(pd->key_serial, (char *) pd->authtok, - pd->authtok_size); - keyrevoke = keyctl_revoke(pd->key_serial); + errno_t ret; + + keysize = keyctl_read_alloc(pd->key_serial, (void **)&password); if (keysize == -1) { ret = errno; DEBUG(1, ("keyctl_read failed [%d][%s].\n", ret, strerror(ret))); return; - } else if (keysize != pd->authtok_size) { - DEBUG(1, ("keyctl_read returned key with wrong size, " - "expect [%d] got [%d].\n", pd->authtok_size, keysize)); + } + + ret = sss_authtok_set_password(pd, &pd->authtok, password, keysize); + safezero(password, keysize); + free(password); + if (ret) { + DEBUG(1, ("failed to set password in auth token [%d][%s].\n", + ret, strerror(ret))); return; } + + keyrevoke = keyctl_revoke(pd->key_serial); if (keyrevoke == -1) { ret = errno; DEBUG(1, ("keyctl_revoke failed [%d][%s].\n", ret, strerror(ret))); @@ -244,8 +246,8 @@ errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx, return EINVAL; }
- if (pd->authtok_size == 0 || pd->authtok == NULL) { - DEBUG(1, ("Missing authtok for user [%s].\n", pd->user)); + if (sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { + DEBUG(1, ("Invalid authtok for user [%s].\n", pd->user)); return EINVAL; }
@@ -257,17 +259,29 @@ errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx,
#ifdef USE_KEYRING - new_pd->key_serial = add_key("user", new_pd->user, new_pd->authtok, - new_pd->authtok_size, KEY_SPEC_SESSION_KEYRING); + const char *password; + size_t len; + + ret = sss_authtok_get_password(&new_pd->authtok, &password, &len); + if (ret) { + DEBUG(1, ("Failed to get password [%d][%s].\n", ret, strerror(ret))); + sss_authtok_set_empty(&new_pd->authtok); + talloc_free(new_pd); + return ret; + } + + new_pd->key_serial = add_key("user", new_pd->user, password, len, + KEY_SPEC_SESSION_KEYRING); if (new_pd->key_serial == -1) { ret = errno; - DEBUG(1, ("add_key fialed [%d][%s].\n", ret, strerror(ret))); + DEBUG(1, ("add_key failed [%d][%s].\n", ret, strerror(ret))); + sss_authtok_set_empty(&new_pd->authtok); talloc_free(new_pd); return ret; } DEBUG(9, ("Saved authtok of user [%s] with serial [%ld].\n", new_pd->user, new_pd->key_serial)); - memset(new_pd->authtok, 0, new_pd->authtok_size); + sss_authtok_set_empty(&new_pd->authtok); #endif
key.type = HASH_KEY_ULONG; diff --git a/src/providers/krb5/krb5_renew_tgt.c b/src/providers/krb5/krb5_renew_tgt.c index ccb7e6af6d05121292d1152977c319daf660c9ef..4a812ab04d028961914557522423be82a1a01941 100644 --- a/src/providers/krb5/krb5_renew_tgt.c +++ b/src/providers/krb5/krb5_renew_tgt.c @@ -593,22 +593,14 @@ errno_t add_tgt_to_renew_table(struct krb5_ctx *krb5_ctx, const char *ccfile, goto done; }
- if (renew_data->pd->newauthtok_type != SSS_AUTHTOK_TYPE_EMPTY) { - talloc_zfree(renew_data->pd->newauthtok); - renew_data->pd->newauthtok_size = 0; - renew_data->pd->newauthtok_type = SSS_AUTHTOK_TYPE_EMPTY; - } + sss_authtok_set_empty(&renew_data->pd->newauthtok);
- talloc_zfree(renew_data->pd->authtok); - renew_data->pd->authtok = (uint8_t *) talloc_strdup(renew_data->pd, - renew_data->ccfile); - if (renew_data->pd->authtok == NULL) { - DEBUG(1, ("talloc_strdup failed.\n")); - ret = ENOMEM; + ret = sss_authtok_set_ccfile(renew_data->pd, &renew_data->pd->authtok, + renew_data->ccfile, 0); + if (ret) { + DEBUG(1, ("Failed to store ccfile in auth token.\n")); goto done; } - renew_data->pd->authtok_size = strlen((char *) renew_data->pd->authtok) + 1; - renew_data->pd->authtok_type = SSS_AUTHTOK_TYPE_CCFILE;
renew_data->pd->cmd = SSS_CMD_RENEW;
diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c index 32a2e04ea959a3cc81b88f5b2b19575c813e8adf..98483fee0da418523e78152861d489988eb9c6c2 100644 --- a/src/providers/ldap/ldap_auth.c +++ b/src/providers/ldap/ldap_auth.c @@ -462,7 +462,7 @@ struct auth_state { struct tevent_context *ev; struct sdap_auth_ctx *ctx; const char *username; - struct dp_opt_blob password; + struct sss_auth_token *authtok; struct sdap_service *sdap_service;
struct sdap_handle *sh; @@ -484,7 +484,7 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx, struct tevent_context *ev, struct sdap_auth_ctx *ctx, const char *username, - struct dp_opt_blob password, + struct sss_auth_token *authtok, bool try_chpass_service) { struct tevent_req *req; @@ -493,8 +493,8 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx, req = tevent_req_create(memctx, &state, struct auth_state); if (!req) return NULL;
- /* Treat a zero-length password as a failure */ - if (password.length == 0) { + /* The token must be a password token */ + if (sss_authtok_get_type(authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { state->result = SDAP_AUTH_FAILED; tevent_req_done(req); return tevent_req_post(req, ev); @@ -503,7 +503,7 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx, state->ev = ev; state->ctx = ctx; state->username = username; - state->password = password; + state->authtok = authtok; state->srv = NULL; if (try_chpass_service && ctx->chpass_service != NULL && ctx->chpass_service->name != NULL) { @@ -632,7 +632,7 @@ static void auth_connect_done(struct tevent_req *subreq)
subreq = sdap_auth_send(state, state->ev, state->sh, NULL, NULL, state->dn, - "password", state->password); + state->authtok); if (!subreq) { tevent_req_error(req, ENOMEM); return; @@ -727,8 +727,6 @@ struct sdap_pam_chpass_state { struct pam_data *pd; const char *username; char *dn; - char *password; - char *new_password; struct sdap_handle *sh;
struct sdap_auth_ctx *ctx; @@ -744,7 +742,6 @@ void sdap_pam_chpass_handler(struct be_req *breq) struct sdap_auth_ctx *ctx; struct tevent_req *subreq; struct pam_data *pd; - struct dp_opt_blob authtok; int dp_err = DP_ERR_FATAL;
ctx = talloc_get_type(breq->be_ctx->bet_info[BET_CHPASS].pvt_bet_data, @@ -758,8 +755,8 @@ void sdap_pam_chpass_handler(struct be_req *breq) goto done; }
- if (pd->priv == 1 && pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM && - pd->authtok_size == 0) { + if ((pd->priv == 1) && (pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) && + (sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD)) { DEBUG(4, ("Password reset by root is not supported.\n")); pd->pam_status = PAM_PERM_DENIED; dp_err = DP_ERR_OK; @@ -782,25 +779,9 @@ void sdap_pam_chpass_handler(struct be_req *breq) state->pd = pd; state->username = pd->user; state->ctx = ctx; - state->password = talloc_strndup(state, - (char *)pd->authtok, pd->authtok_size); - if (!state->password) goto done; - talloc_set_destructor((TALLOC_CTX *)state->password, - password_destructor);
- if (pd->cmd == SSS_PAM_CHAUTHTOK) { - state->new_password = talloc_strndup(state, - (char *)pd->newauthtok, - pd->newauthtok_size); - if (!state->new_password) goto done; - talloc_set_destructor((TALLOC_CTX *)state->new_password, - password_destructor); - } - - authtok.data = (uint8_t *)state->password; - authtok.length = strlen(state->password); - subreq = auth_send(breq, breq->be_ctx->ev, - ctx, state->username, authtok, true); + subreq = auth_send(breq, breq->be_ctx->ev, ctx, + state->username, &pd->authtok, true); if (!subreq) goto done;
tevent_req_set_callback(subreq, sdap_auth4chpass_done, state); @@ -887,18 +868,30 @@ static void sdap_auth4chpass_done(struct tevent_req *req) state->pd->pam_status = PAM_MODULE_UNKNOWN; goto done; } else { + const char *password; + const char *new_password; + + ret = sss_authtok_get_password(&state->pd->authtok, + &password, NULL); + if (ret) { + state->pd->pam_status = PAM_SYSTEM_ERR; + goto done; + } + ret = sss_authtok_get_password(&state->pd->newauthtok, + &new_password, NULL); + if (ret) { + state->pd->pam_status = PAM_SYSTEM_ERR; + goto done; + } + subreq = sdap_exop_modify_passwd_send(state, state->breq->be_ctx->ev, - state->sh, - state->dn, - state->password, - state->new_password); - + state->sh, state->dn, + password, new_password); if (!subreq) { DEBUG(2, ("Failed to change password for %s\n", state->username)); goto done; } - tevent_req_set_callback(subreq, sdap_pam_chpass_done, state); return; } @@ -1013,8 +1006,6 @@ done: struct sdap_pam_auth_state { struct be_req *breq; struct pam_data *pd; - const char *username; - struct dp_opt_blob password; };
static void sdap_pam_auth_done(struct tevent_req *req); @@ -1049,12 +1040,9 @@ void sdap_pam_auth_handler(struct be_req *breq)
state->breq = breq; state->pd = pd; - state->username = pd->user; - state->password.data = pd->authtok; - state->password.length = pd->authtok_size;
subreq = auth_send(breq, breq->be_ctx->ev, ctx, - state->username, state->password, + pd->user, &pd->authtok, pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM ? true : false); if (!subreq) goto done;
@@ -1088,6 +1076,7 @@ static void sdap_pam_auth_done(struct tevent_req *req) enum pwexpire pw_expire_type; struct be_ctx *be_ctx = state->breq->be_ctx; void *pw_expire_data; + const char *password; int dp_err = DP_ERR_OK; int ret;
@@ -1170,26 +1159,19 @@ static void sdap_pam_auth_done(struct tevent_req *req) if (result == SDAP_AUTH_SUCCESS && state->breq->be_ctx->domain->cache_credentials) {
- char *password = talloc_strndup(state, (char *) - state->password.data, - state->password.length); - /* password caching failures are not fatal errors */ - if (!password) { - DEBUG(2, ("Failed to cache password for %s\n", state->username)); - goto done; + ret = sss_authtok_get_password(&state->pd->authtok, &password, NULL); + if (ret == EOK) { + ret = sysdb_cache_password(state->breq->be_ctx->sysdb, + state->pd->user, password); } - talloc_set_destructor((TALLOC_CTX *)password, password_destructor); - - ret = sysdb_cache_password(state->breq->be_ctx->sysdb, - state->username, password);
/* password caching failures are not fatal errors */ if (ret != EOK) { DEBUG(2, ("Failed to cache password for %s\n", - state->username)); + state->pd->user)); } else { DEBUG(4, ("Password successfully cached for %s\n", - state->username)); + state->pd->user)); } goto done; } diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c index e0440625d279fbbaa1cc2e6343b73f5a247371f7..84497b75ef586b58e27cc4dc9e6b8b3244464676 100644 --- a/src/providers/ldap/sdap_async.c +++ b/src/providers/ldap/sdap_async.c @@ -502,8 +502,8 @@ struct tevent_req *sdap_exop_modify_passwd_send(TALLOC_CTX *memctx, struct tevent_context *ev, struct sdap_handle *sh, char *user_dn, - char *password, - char *new_password) + const char *password, + const char *new_password) { struct tevent_req *req = NULL; struct sdap_exop_modify_passwd_state *state; diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h index 8c16d94e6486336e92b6112cd8b5a2dff4c97957..c5dc17037cd6d2c4ae88aa60d43d517eb2958085 100644 --- a/src/providers/ldap/sdap_async.h +++ b/src/providers/ldap/sdap_async.h @@ -108,8 +108,7 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, const char *sasl_mech, const char *sasl_user, const char *user_dn, - const char *authtok_type, - struct dp_opt_blob authtok); + struct sss_auth_token *authtok);
int sdap_auth_recv(struct tevent_req *req, TALLOC_CTX *memctx, @@ -128,8 +127,8 @@ struct tevent_req *sdap_exop_modify_passwd_send(TALLOC_CTX *memctx, struct tevent_context *ev, struct sdap_handle *sh, char *user_dn, - char *password, - char *new_password); + const char *password, + const char *new_password); int sdap_exop_modify_passwd_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, enum sdap_result *result, char **user_error_msg); diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c index 79ad3b8e4c7720982944e502c4424d61dd1f1295..8899e2944808cf6a0ea6c10bb6bc2de46702b106 100644 --- a/src/providers/ldap/sdap_async_connection.c +++ b/src/providers/ldap/sdap_async_connection.c @@ -493,7 +493,7 @@ static struct tevent_req *simple_bind_send(TALLOC_CTX *memctx, DEBUG(4, ("Executing simple bind as: %s\n", state->user_dn));
ret = ldap_sasl_bind(state->sh->ldap, state->user_dn, LDAP_SASL_SIMPLE, - state->pw, request_controls, NULL, &msgid); + pw, request_controls, NULL, &msgid); if (ctrls[0]) ldap_control_free(ctrls[0]); if (ret == -1 || msgid == -1) { ret = ldap_get_option(state->sh->ldap, @@ -1082,18 +1082,12 @@ int sdap_kinit_recv(struct tevent_req *req, /* ==Authenticaticate-User-by-DN========================================== */
struct sdap_auth_state { - const char *user_dn; - struct berval pw; struct sdap_ppolicy_data *ppolicy; - - int result; bool is_sasl; + int result; };
static void sdap_auth_done(struct tevent_req *subreq); -static int sdap_auth_get_authtok(const char *authtok_type, - struct dp_opt_blob authtok, - struct berval *pw);
/* TODO: handle sasl_cred */ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, @@ -1102,31 +1096,14 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, const char *sasl_mech, const char *sasl_user, const char *user_dn, - const char *authtok_type, - struct dp_opt_blob authtok) + struct sss_auth_token *authtok) { struct tevent_req *req, *subreq; struct sdap_auth_state *state; - int ret;
req = tevent_req_create(memctx, &state, struct sdap_auth_state); if (!req) return NULL;
- state->user_dn = user_dn; - - ret = sdap_auth_get_authtok(authtok_type, authtok, &state->pw); - if (ret != EOK) { - if (ret == ENOSYS) { - DEBUG(1, ("Getting authtok is not supported with the " - "crypto library compiled with, authentication " - "might fail!\n")); - } else { - DEBUG(1, ("Cannot parse authtok.\n")); - tevent_req_error(req, ret); - return tevent_req_post(req, ev); - } - } - if (sasl_mech) { state->is_sasl = true; subreq = sasl_bind_send(state, ev, sh, sasl_mech, sasl_user, NULL); @@ -1135,8 +1112,27 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, return tevent_req_post(req, ev); } } else { + const char *password = NULL; + struct berval pw; + size_t pwlen; + errno_t ret; + + ret = sss_authtok_get_password(authtok, &password, &pwlen); + if (ret != EOK) { + DEBUG(1, ("Cannot parse authtok.\n")); + tevent_req_error(req, ret); + return tevent_req_post(req, ev); + } + /* Treat a zero-length password as a failure */ + if (*password == '\0') { + tevent_req_error(req, ENOENT); + return tevent_req_post(req, ev); + } + pw.bv_val = discard_const(password); + pw.bv_len = pwlen - 1; + state->is_sasl = false; - subreq = simple_bind_send(state, ev, sh, user_dn, &state->pw); + subreq = simple_bind_send(state, ev, sh, user_dn, &pw); if (!subreq) { tevent_req_error(req, ENOMEM); return tevent_req_post(req, ev); @@ -1598,6 +1594,10 @@ static void sdap_cli_auth_step(struct tevent_req *req) SDAP_SASL_MECH); const char *user_dn = dp_opt_get_string(state->opts->basic, SDAP_DEFAULT_BIND_DN); + const char *authtok_type; + struct dp_opt_blob authtok_blob; + struct sss_auth_token authtok = { 0 }; + errno_t ret;
if (!state->do_auth || (sasl_mech == NULL && user_dn == NULL)) { @@ -1617,17 +1617,31 @@ static void sdap_cli_auth_step(struct tevent_req *req) state->sh->expire_time = now + expire_timeout; }
- subreq = sdap_auth_send(state, - state->ev, - state->sh, - sasl_mech, + authtok_type = dp_opt_get_string(state->opts->basic, + SDAP_DEFAULT_AUTHTOK_TYPE); + if (authtok_type != NULL) { + if (strcasecmp(authtok_type, "password") != 0) { + DEBUG(SSSDBG_TRACE_LIBS, ("Invalid authtoken type\n")); + tevent_req_error(req, EINVAL); + return; + } + authtok_blob = dp_opt_get_blob(state->opts->basic, + SDAP_DEFAULT_AUTHTOK); + + ret = sss_authtok_set_password(state, &authtok, + (const char *)authtok_blob.data, + authtok_blob.length); + if (ret) { + tevent_req_error(req, ret); + return; + } + } + + subreq = sdap_auth_send(state, state->ev, + state->sh, sasl_mech, dp_opt_get_string(state->opts->basic, - SDAP_SASL_AUTHID), - user_dn, - dp_opt_get_string(state->opts->basic, - SDAP_DEFAULT_AUTHTOK_TYPE), - dp_opt_get_blob(state->opts->basic, - SDAP_DEFAULT_AUTHTOK)); + SDAP_SASL_AUTHID), + user_dn, &authtok); if (!subreq) { tevent_req_error(req, ENOMEM); return; diff --git a/src/providers/proxy/proxy.h b/src/providers/proxy/proxy.h index cea03382517231cdf2b96069ab93dfb7967b46a6..962cb28fc7d6362c45d268f289ffbce103a6e738 100644 --- a/src/providers/proxy/proxy.h +++ b/src/providers/proxy/proxy.h @@ -89,11 +89,8 @@ struct proxy_nss_ops { };
struct authtok_conv { - uint32_t authtok_size; - uint8_t *authtok; - - uint32_t newauthtok_size; - uint8_t *newauthtok; + struct sss_auth_token authtok; + struct sss_auth_token newauthtok;
bool sent_old; }; diff --git a/src/providers/proxy/proxy_auth.c b/src/providers/proxy/proxy_auth.c index 8088283fa8147f75b7d8eb4c83c63208163c9375..3430f38b282eff2da24735f8d635a952edde8888 100644 --- a/src/providers/proxy/proxy_auth.c +++ b/src/providers/proxy/proxy_auth.c @@ -712,7 +712,7 @@ static void proxy_child_done(struct tevent_req *req) struct proxy_client_ctx *client_ctx = tevent_req_callback_data(req, struct proxy_client_ctx); struct pam_data *pd = NULL; - char *password; + const char *password; int ret; struct tevent_immediate *imm;
@@ -747,17 +747,15 @@ static void proxy_child_done(struct tevent_req *req)
/* Check if we need to save the cached credentials */ if ((pd->cmd == SSS_PAM_AUTHENTICATE || pd->cmd == SSS_PAM_CHAUTHTOK) && - pd->pam_status == PAM_SUCCESS && - client_ctx->be_req->be_ctx->domain->cache_credentials) { - password = talloc_strndup(client_ctx->be_req, - (char *) pd->authtok, - pd->authtok_size); - if (!password) { + (pd->pam_status == PAM_SUCCESS) && + client_ctx->be_req->be_ctx->domain->cache_credentials) { + + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + if (ret) { /* password caching failures are not fatal errors */ DEBUG(2, ("Failed to cache password\n")); goto done; } - talloc_set_destructor((TALLOC_CTX *)password, password_destructor);
ret = sysdb_cache_password(client_ctx->be_req->be_ctx->sysdb, pd->user, password); diff --git a/src/providers/proxy/proxy_child.c b/src/providers/proxy/proxy_child.c index c575948a7036d9b73d93bd00e111834b12d28e7d..556dbf9b5488d75f0fa60386958f61b95d61fba2 100644 --- a/src/providers/proxy/proxy_child.c +++ b/src/providers/proxy/proxy_child.c @@ -80,6 +80,9 @@ static int proxy_internal_conv(int num_msg, const struct pam_message **msgm, int i; struct pam_response *reply; struct authtok_conv *auth_data; + const char *password; + size_t pwlen; + errno_t ret;
auth_data = talloc_get_type(appdata_ptr, struct authtok_conv);
@@ -94,11 +97,13 @@ static int proxy_internal_conv(int num_msg, const struct pam_message **msgm, case PAM_PROMPT_ECHO_OFF: DEBUG(4, ("Conversation message: [%s]\n", msgm[i]->msg)); reply[i].resp_retcode = 0; - reply[i].resp = calloc(auth_data->authtok_size + 1, - sizeof(char)); + + ret = sss_authtok_get_password(&auth_data->authtok, + &password, &pwlen); + if (ret) goto failed; + reply[i].resp = calloc(pwlen + 1, sizeof(char)); if (reply[i].resp == NULL) goto failed; - memcpy(reply[i].resp, auth_data->authtok, - auth_data->authtok_size); + memcpy(reply[i].resp, password, pwlen + 1);
break; default: @@ -124,6 +129,9 @@ static int proxy_chauthtok_conv(int num_msg, const struct pam_message **msgm, int i; struct pam_response *reply; struct authtok_conv *auth_data; + const char *password; + size_t pwlen; + errno_t ret;
auth_data = talloc_get_type(appdata_ptr, struct authtok_conv);
@@ -141,20 +149,23 @@ static int proxy_chauthtok_conv(int num_msg, const struct pam_message **msgm, reply[i].resp_retcode = 0; if (!auth_data->sent_old) { /* The first prompt will be asking for the old authtok */ - reply[i].resp = calloc(auth_data->authtok_size + 1, - sizeof(char)); + ret = sss_authtok_get_password(&auth_data->authtok, + &password, &pwlen); + if (ret) goto failed; + reply[i].resp = calloc(pwlen + 1, sizeof(char)); if (reply[i].resp == NULL) goto failed; - memcpy(reply[i].resp, auth_data->authtok, - auth_data->authtok_size); + memcpy(reply[i].resp, password, pwlen + 1); auth_data->sent_old = true; } else { /* Subsequent prompts are looking for the new authtok */ - reply[i].resp = calloc(auth_data->newauthtok_size + 1, - sizeof(char)); + ret = sss_authtok_get_password(&auth_data->newauthtok, + &password, &pwlen); + if (ret) goto failed; + reply[i].resp = calloc(pwlen + 1, sizeof(char)); if (reply[i].resp == NULL) goto failed; - memcpy(reply[i].resp, auth_data->newauthtok, - auth_data->newauthtok_size); + memcpy(reply[i].resp, password, pwlen + 1); + auth_data->sent_old = true; }
break; @@ -213,8 +224,8 @@ static errno_t call_pam_stack(const char *pam_target, struct pam_data *pd) } switch (pd->cmd) { case SSS_PAM_AUTHENTICATE: - auth_data->authtok_size = pd->authtok_size; - auth_data->authtok = pd->authtok; + sss_authtok_copy(auth_data, &pd->authtok, + &auth_data->authtok); pam_status = pam_authenticate(pamh, 0); break; case SSS_PAM_SETCRED: @@ -230,21 +241,21 @@ static errno_t call_pam_stack(const char *pam_target, struct pam_data *pd) pam_status=pam_close_session(pamh, 0); break; case SSS_PAM_CHAUTHTOK: - auth_data->authtok_size = pd->authtok_size; - auth_data->authtok = pd->authtok; + sss_authtok_copy(auth_data, &pd->authtok, + &auth_data->authtok); if (pd->priv != 1) { pam_status = pam_authenticate(pamh, 0); auth_data->sent_old = false; if (pam_status != PAM_SUCCESS) break; } - auth_data->newauthtok_size = pd->newauthtok_size; - auth_data->newauthtok = pd->newauthtok; + sss_authtok_copy(auth_data, &pd->newauthtok, + &auth_data->newauthtok); pam_status = pam_chauthtok(pamh, 0); break; case SSS_PAM_CHAUTHTOK_PRELIM: if (pd->priv != 1) { - auth_data->authtok_size = pd->authtok_size; - auth_data->authtok = pd->authtok; + sss_authtok_copy(auth_data, &pd->authtok, + &auth_data->authtok); pam_status = pam_authenticate(pamh, 0); } else { pam_status = PAM_SUCCESS; diff --git a/src/responder/pam/pam_LOCAL_domain.c b/src/responder/pam/pam_LOCAL_domain.c index 71446b4f8da53bfe4c0707621fafb228da5f808c..23eb7a2a8ddd3ae4480030633be867564b7f59f2 100644 --- a/src/responder/pam/pam_LOCAL_domain.c +++ b/src/responder/pam/pam_LOCAL_domain.c @@ -154,22 +154,19 @@ static void do_pam_acct_mgmt(struct LOCAL_request *lreq) static void do_pam_chauthtok(struct LOCAL_request *lreq) { int ret; - char *newauthtok; + const char *password; char *salt; char *new_hash; struct pam_data *pd;
pd = lreq->preq->pd;
- newauthtok = talloc_strndup(lreq, (char *) pd->newauthtok, - pd->newauthtok_size); - NULL_CHECK_OR_JUMP(newauthtok, ("talloc_strndup failed.\n"), lreq->error, - ENOMEM, done); - memset(pd->newauthtok, 0, pd->newauthtok_size); - - if (strlen(newauthtok) == 0) { + ret = sss_authtok_get_password(&pd->newauthtok, &password, NULL); + if (ret) { /* TODO: should we allow null passwords via a config option ? */ - DEBUG(1, ("Empty passwords are not allowed!\n")); + if (ret == ENOENT) { + DEBUG(1, ("Empty passwords are not allowed!\n")); + } lreq->error = EINVAL; goto done; } @@ -179,11 +176,10 @@ static void do_pam_chauthtok(struct LOCAL_request *lreq) lreq->error, ret, done); DEBUG(4, ("Using salt [%s]\n", salt));
- ret = s3crypt_sha512(lreq, newauthtok, salt, &new_hash); + ret = s3crypt_sha512(lreq, password, salt, &new_hash); NEQ_CHECK_OR_JUMP(ret, EOK, ("Hash generation failed.\n"), lreq->error, ret, done); DEBUG(4, ("New hash [%s]\n", new_hash)); - memset(newauthtok, 0, pd->newauthtok_size);
lreq->mod_attrs = sysdb_new_attrs(lreq); NULL_CHECK_OR_JUMP(lreq->mod_attrs, ("sysdb_new_attrs failed.\n"), @@ -204,7 +200,7 @@ static void do_pam_chauthtok(struct LOCAL_request *lreq) lreq->error, ret, done);
done: - return; + sss_authtok_set_empty(&pd->newauthtok); }
int LOCAL_pam_handler(struct pam_auth_req *preq) @@ -223,9 +219,9 @@ int LOCAL_pam_handler(struct pam_auth_req *preq) NULL}; struct ldb_result *res; const char *username = NULL; - const char *password = NULL; + const char *pwdhash = NULL; char *new_hash = NULL; - char *authtok = NULL; + const char *password; struct pam_data *pd = preq->pd; int ret;
@@ -287,25 +283,22 @@ int LOCAL_pam_handler(struct pam_auth_req *preq) DEBUG(4, ("allowing root to reset a password.\n")); break; } - authtok = talloc_strndup(lreq, (char *) pd->authtok, - pd->authtok_size); - NULL_CHECK_OR_JUMP(authtok, ("talloc_strndup failed.\n"), - lreq->error, ENOMEM, done); - memset(pd->authtok, 0, pd->authtok_size); + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + NEQ_CHECK_OR_JUMP(ret, EOK, ("Failed to get password.\n"), + lreq->error, ret, done);
- password = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_PWD, NULL); - NULL_CHECK_OR_JUMP(password, ("No password stored.\n"), + pwdhash = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_PWD, NULL); + NULL_CHECK_OR_JUMP(pwdhash, ("No password stored.\n"), lreq->error, LDB_ERR_NO_SUCH_ATTRIBUTE, done); - DEBUG(4, ("user: [%s], password hash: [%s]\n", username, password)); + DEBUG(4, ("user: [%s], password hash: [%s]\n", username, pwdhash));
- ret = s3crypt_sha512(lreq, authtok, password, &new_hash); - memset(authtok, 0, pd->authtok_size); + ret = s3crypt_sha512(lreq, password, pwdhash, &new_hash); NEQ_CHECK_OR_JUMP(ret, EOK, ("nss_sha512_crypt failed.\n"), lreq->error, ret, done);
DEBUG(4, ("user: [%s], new hash: [%s]\n", username, new_hash));
- if (strcmp(new_hash, password) != 0) { + if (strcmp(new_hash, pwdhash) != 0) { DEBUG(1, ("Passwords do not match.\n")); do_failed_login(lreq); goto done; @@ -338,13 +331,8 @@ int LOCAL_pam_handler(struct pam_auth_req *preq) }
done: - if (pd->authtok != NULL) - memset(pd->authtok, 0, pd->authtok_size); - if (authtok != NULL) - memset(authtok, 0, pd->authtok_size); - if (pd->newauthtok != NULL) - memset(pd->newauthtok, 0, pd->newauthtok_size); - + sss_authtok_set_empty(&pd->newauthtok); + sss_authtok_set_empty(&pd->authtok); prepare_reply(lreq); return EOK; } diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index b95553b3d7da51127ca7614ebdf062bd45c484cf..ed23b51a6f17047c27e0831c75af587e5e30e4fd 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -48,21 +48,38 @@ enum pam_verbosity {
static void pam_reply(struct pam_auth_req *preq);
-static int extract_authtok(uint32_t *type, uint32_t *size, uint8_t **tok, - size_t data_size, uint8_t *body, size_t blen, - size_t *c) { +static int extract_authtok_v2(TALLOC_CTX *mem_ctx, struct sss_auth_token *tok, + size_t data_size, uint8_t *body, size_t blen, + size_t *c) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + uint8_t *auth_token_data; + int ret = EOK;
if (data_size < sizeof(uint32_t) || *c+data_size > blen || SIZE_T_OVERFLOW(*c, data_size)) return EINVAL; - *size = data_size - sizeof(uint32_t);
- SAFEALIGN_COPY_UINT32_CHECK(type, &body[*c], blen, c); + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, &body[*c], blen, c); + auth_token_length = data_size - sizeof(uint32_t); + auth_token_data = body+(*c);
- *tok = body+(*c); + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_set_password(mem_ctx, tok, + (const char *)auth_token_data, + auth_token_length); + break; + default: + return EINVAL; + }
- *c += (*size); + *c += auth_token_length;
- return EOK; + return ret; }
static int extract_string(char **var, size_t size, uint8_t *body, size_t blen, @@ -184,14 +201,13 @@ static int pam_parse_in_data_v2(struct sss_domain_info *domains, if (ret != EOK) return ret; break; case SSS_PAM_ITEM_AUTHTOK: - ret = extract_authtok(&pd->authtok_type, &pd->authtok_size, - &pd->authtok, size, body, blen, &c); + ret = extract_authtok_v2(pd, &pd->authtok, + size, body, blen, &c); if (ret != EOK) return ret; break; case SSS_PAM_ITEM_NEWAUTHTOK: - ret = extract_authtok(&pd->newauthtok_type, - &pd->newauthtok_size, - &pd->newauthtok, size, body, blen, &c); + ret = extract_authtok_v2(pd, &pd->newauthtok, + size, body, blen, &c); if (ret != EOK) return ret; break; default: @@ -231,14 +247,44 @@ static int pam_parse_in_data_v3(struct sss_domain_info *domains, return EOK; }
+static int extract_authtok_v1(TALLOC_CTX *mem_ctx, struct sss_auth_token *tok, + uint8_t *body, size_t blen, size_t *c) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + uint8_t *auth_token_data; + int ret = EOK; + + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, &body[*c], blen, c); + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_length, &body[*c], blen, c); + auth_token_data = body+(*c); + + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_set_password(mem_ctx, tok, + (const char *)auth_token_data, + auth_token_length); + break; + default: + return EINVAL; + } + + *c += auth_token_length; + + return ret; +} + static int pam_parse_in_data(struct sss_domain_info *domains, const char *default_domain, struct pam_data *pd, uint8_t *body, size_t blen) { - int start; - int end; - int last; + size_t start; + size_t end; + size_t last; int ret;
last = blen - 1; @@ -268,45 +314,15 @@ static int pam_parse_in_data(struct sss_domain_info *domains, if (body[end++] != '\0') return EINVAL; pd->rhost = (char *) &body[start];
- start = end; - pd->authtok_type = (int) body[start]; - - start += sizeof(uint32_t); - pd->authtok_size = (int) body[start]; - if (pd->authtok_size >= blen) return EINVAL; - - start += sizeof(uint32_t); - end = start + pd->authtok_size; - if (pd->authtok_size == 0) { - pd->authtok = NULL; - } else { - if (end <= blen) { - pd->authtok = (uint8_t *) &body[start]; - } else { - DEBUG(1, ("Invalid authtok size: %d\n", pd->authtok_size)); - return EINVAL; - } + ret = extract_authtok_v1(pd, &pd->authtok, body, blen, &end); + if (ret) { + DEBUG(1, ("Invalid auth token\n")); + return ret; } - - start = end; - pd->newauthtok_type = (int) body[start]; - - start += sizeof(uint32_t); - pd->newauthtok_size = (int) body[start]; - if (pd->newauthtok_size >= blen) return EINVAL; - - start += sizeof(uint32_t); - end = start + pd->newauthtok_size; - - if (pd->newauthtok_size == 0) { - pd->newauthtok = NULL; - } else { - if (end <= blen) { - pd->newauthtok = (uint8_t *) &body[start]; - } else { - DEBUG(1, ("Invalid newauthtok size: %d\n", pd->newauthtok_size)); - return EINVAL; - } + ret = extract_authtok_v1(pd, &pd->newauthtok, body, blen, &end); + if (ret) { + DEBUG(1, ("Invalid new auth token\n")); + return ret; }
DEBUG_PAM_DATA(4, pd); @@ -762,9 +778,9 @@ static void pam_reply(struct pam_auth_req *preq) goto done; }
- password = talloc_strndup(preq, pd->authtok, pd->authtok_size); - if (!password) { - DEBUG(0, ("Fatal: Out of memory copying password\n")); + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + if (ret) { + DEBUG(0, ("Failed to get password.\n")); goto done; }
@@ -774,10 +790,6 @@ static void pam_reply(struct pam_auth_req *preq) &exp_date, &delay_until);
pam_cache_auth_done(preq, ret, exp_date, delay_until); - if (password) { - for (i = 0; password[i]; i++) password[i] = 0; - talloc_zfree(password); - } return; } break; diff --git a/src/tests/krb5_child-test.c b/src/tests/krb5_child-test.c index 34d025b77b27a27e6131c1895c6c02644f921e5d..a72a3519985292456db6b9bbf9bccdcf678068a6 100644 --- a/src/tests/krb5_child-test.c +++ b/src/tests/krb5_child-test.c @@ -167,6 +167,9 @@ create_dummy_pam_data(TALLOC_CTX *mem_ctx, const char *user, const char *password) { struct pam_data *pd; + const char *authtok; + size_t authtok_len; + errno_t ret;
pd = talloc_zero(mem_ctx, struct pam_data); if (!pd) goto fail; @@ -175,12 +178,12 @@ create_dummy_pam_data(TALLOC_CTX *mem_ctx, const char *user, pd->user = talloc_strdup(pd, user); if (!pd->user) goto fail;
- pd->authtok = discard_const(talloc_strdup(pd, password)); - if (!pd->authtok) goto fail; - pd->authtok_size = strlen(password); - pd->authtok_type = SSS_AUTHTOK_TYPE_PASSWORD; + ret = sss_authtok_set_password(pd, &pd->authtok, password, 0); + if (ret) goto fail; + + (void)sss_authtok_get_password(&pd->authtok, &authtok, &authtok_len); DEBUG(SSSDBG_FUNC_DATA, ("Authtok [%s] len [%d]\n", - pd->authtok, pd->authtok_size)); + authtok, (int)authtok_len));
return pd;
Rebased on top of master. Tested and working.
Simo Sorce (4): Code can only check for cached passwords Add function to safely wipe memory. Add authtok utility functions. Change pam data auth tokens.
Makefile.am | 4 + src/db/sysdb.h | 3 +- src/db/sysdb_ops.c | 13 +-- src/providers/data_provider.h | 9 +- src/providers/dp_auth_util.c | 76 +++++--- src/providers/dp_pam_data_util.c | 113 ++++++------ src/providers/ipa/ipa_auth.c | 6 +- src/providers/krb5/krb5_auth.c | 52 +++--- src/providers/krb5/krb5_child.c | 148 ++++++++------- src/providers/krb5/krb5_child_handler.c | 59 +++++- .../krb5/krb5_delayed_online_authentication.c | 50 ++++-- src/providers/krb5/krb5_renew_tgt.c | 18 +-- src/providers/ldap/ldap_auth.c | 90 ++++------ src/providers/ldap/sdap_async.c | 4 +- src/providers/ldap/sdap_async.h | 7 +- src/providers/ldap/sdap_async_connection.c | 88 +++++---- src/providers/proxy/proxy.h | 7 +- src/providers/proxy/proxy_auth.c | 14 +- src/providers/proxy/proxy_child.c | 51 +++-- src/responder/pam/pam_LOCAL_domain.c | 52 ++---- src/responder/pam/pamsrv_cmd.c | 159 +++++++++------- src/tests/krb5_child-test.c | 13 +- src/tests/sysdb-tests.c | 6 +- src/util/authtok.c | 195 ++++++++++++++++++++ src/util/authtok.h | 180 ++++++++++++++++++ src/util/util.c | 9 + src/util/util.h | 9 + 27 files changed, 950 insertions(+), 485 deletions(-) create mode 100644 src/util/authtok.c create mode 100644 src/util/authtok.h
Make it clear to the API users that we can not take arbitrary auth tokens. We can only take a password for now so simplify and clarify the interface. --- src/db/sysdb.h | 3 +-- src/db/sysdb_ops.c | 12 +----------- src/providers/krb5/krb5_auth.c | 21 +++++++++++++++++---- src/responder/pam/pamsrv_cmd.c | 39 ++++++++++++++++++++++++--------------- src/tests/sysdb-tests.c | 6 ++---- 5 files changed, 45 insertions(+), 36 deletions(-)
diff --git a/src/db/sysdb.h b/src/db/sysdb.h index ed00c165952aa80102b88c9e857355f2ef27d570..892414797304a1ba86a041279aea9bcafe1fd3cd 100644 --- a/src/db/sysdb.h +++ b/src/db/sysdb.h @@ -778,8 +778,7 @@ errno_t check_failed_login_attempts(struct confdb_ctx *cdb, time_t *delayed_until); int sysdb_cache_auth(struct sysdb_ctx *sysdb, const char *name, - const uint8_t *authtok, - size_t authtok_size, + const char *password, struct confdb_ctx *cdb, bool just_check, time_t *_expire_date, diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c index 0eef6d039036d1e5657ffb499e8242147b214efb..b09f661c58ea8c3afb03556d084d5eb3b45e33a5 100644 --- a/src/db/sysdb_ops.c +++ b/src/db/sysdb_ops.c @@ -2668,8 +2668,7 @@ done:
int sysdb_cache_auth(struct sysdb_ctx *sysdb, const char *name, - const uint8_t *authtok, - size_t authtok_size, + const char *password, struct confdb_ctx *cdb, bool just_check, time_t *_expire_date, @@ -2684,7 +2683,6 @@ int sysdb_cache_auth(struct sysdb_ctx *sysdb, struct ldb_message *ldb_msg; const char *userhash; char *comphash; - char *password = NULL; uint64_t lastLogin = 0; int cred_expiration; uint32_t failed_login_attempts = 0; @@ -2770,13 +2768,6 @@ int sysdb_cache_auth(struct sysdb_ctx *sysdb,
/* TODO: verify user account (disabled, expired ...) */
- password = talloc_strndup(tmp_ctx, (const char *)authtok, authtok_size); - if (password == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - ret = ENOMEM; - goto done; - } - userhash = ldb_msg_find_attr_as_string(ldb_msg, SYSDB_CACHEDPWD, NULL); if (userhash == NULL || *userhash == '\0') { DEBUG(4, ("Cached credentials not available.\n")); @@ -2860,7 +2851,6 @@ done: if (_delayed_until != NULL) { *_delayed_until = delayed_until; } - if (password) for (i = 0; password[i]; i++) password[i] = 0; if (ret) { ldb_transaction_cancel(sysdb->ldb); } else { diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c index 340b33dd2d747ebf247c87fe154b77bfdc4fe58d..559ad583587ee0490bf9f9614647826d18a94762 100644 --- a/src/providers/krb5/krb5_auth.c +++ b/src/providers/krb5/krb5_auth.c @@ -278,16 +278,23 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, struct pam_data *pd, uid_t uid, int *pam_status, int *dp_err) { + char *password = NULL; errno_t ret;
- ret = sysdb_cache_auth(sysdb, pd->user, pd->authtok, - pd->authtok_size, cdb, true, NULL, - NULL); + password = talloc_strndup(state, pd->authtok, pd->authtok_size); + if (!password) { + DEBUG(0, ("Out of memory copying password\n")); + *pam_status = PAM_SYSTEM_ERR; + *dp_err = DP_ERR_OK; + return; + } + + ret = sysdb_cache_auth(sysdb, pd->user, password, cdb, true, NULL, NULL); if (ret != EOK) { DEBUG(1, ("Offline authentication failed\n")); *pam_status = cached_login_pam_status(ret); *dp_err = DP_ERR_OK; - return; + goto done; }
ret = add_user_to_delayed_online_authentication(krb5_ctx, pd, uid); @@ -297,6 +304,12 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, } *pam_status = PAM_AUTHINFO_UNAVAIL; *dp_err = DP_ERR_OFFLINE; + +done: + if (password) { + for (i = 0; password[i]; i++) password[i] = 0; + talloc_zfree(password); + } }
static errno_t krb5_auth_prepare_ccache_file(struct krb5child_req *kr, diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index 4269642206cc0295c0046de4e59a3ad8f1044d1a..ed7438f8d1509568bcd12bbbe7ab73984780bcdd 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -733,7 +733,6 @@ static void pam_reply(struct pam_auth_req *preq) struct timeval tv; struct tevent_timer *te; struct pam_data *pd; - struct sysdb_ctx *sysdb; struct pam_ctx *pctx; uint32_t user_info_type; time_t exp_date = -1; @@ -753,24 +752,34 @@ static void pam_reply(struct pam_auth_req *preq) if ((preq->domain != NULL) && (preq->domain->cache_credentials == true) && (pd->offline_auth == false)) { + const char *password = NULL;
- /* do auth with offline credentials */ - pd->offline_auth = true; + /* do auth with offline credentials */ + pd->offline_auth = true;
- sysdb = preq->domain->sysdb; - if (sysdb == NULL) { - DEBUG(0, ("Fatal: Sysdb CTX not found for " - "domain [%s]!\n", preq->domain->name)); - goto done; - } + if (preq->domain->sysdb == NULL) { + DEBUG(0, ("Fatal: Sysdb CTX not found for domain" + " [%s]!\n", preq->domain->name)); + goto done; + }
- ret = sysdb_cache_auth(sysdb, pd->user, - pd->authtok, pd->authtok_size, - pctx->rctx->cdb, false, - &exp_date, &delay_until); + password = talloc_strndup(preq, pd->authtok, pd->authtok_size); + if (!password) { + DEBUG(0, ("Fatal: Out of memory copying password\n")); + goto done; + }
- pam_handle_cached_login(preq, ret, exp_date, delay_until); - return; + ret = sysdb_cache_auth(preq->domain->sysdb, + pd->user, password, + pctx->rctx->cdb, false, + &exp_date, &delay_until); + + pam_handle_cached_login(preq, ret, exp_date, delay_until); + if (password) { + for (i = 0; password[i]; i++) password[i] = 0; + talloc_zfree(password); + } + return; } break; case SSS_PAM_CHAUTHTOK_PRELIM: diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c index 61047706315d0b9ba94943b10f9d856dfc6fddf8..ec82c8177719b1a04790a2f4a65a859f58be7945 100644 --- a/src/tests/sysdb-tests.c +++ b/src/tests/sysdb-tests.c @@ -1492,8 +1492,7 @@ static void cached_authentication_without_expiration(const char *username, return; }
- ret = sysdb_cache_auth(test_ctx->sysdb, data->username, - (const uint8_t *)password, strlen(password), + ret = sysdb_cache_auth(test_ctx->sysdb, data->username, password, test_ctx->confdb, false, &expire_date, &delayed_until);
fail_unless(ret == expected_result, "sysdb_cache_auth request does not " @@ -1552,8 +1551,7 @@ static void cached_authentication_with_expiration(const char *username, data->attrs, SYSDB_MOD_REP); fail_unless(ret == EOK, "Could not modify user %s", data->username);
- ret = sysdb_cache_auth(test_ctx->sysdb, data->username, - (const uint8_t *) password, strlen(password), + ret = sysdb_cache_auth(test_ctx->sysdb, data->username, password, test_ctx->confdb, false, &expire_date, &delayed_until);
fail_unless(ret == expected_result,
This is useful for wiping passwords, as it prevents the compiler from optimizing out a memset to zero before a free() --- src/util/util.c | 9 +++++++++ src/util/util.h | 9 +++++++++ 2 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/src/util/util.c b/src/util/util.c index ab980775a1e4c87b16d32220bccda6cb644e0756..f268fbcd564cd93a2e63097c595cf19b65eb6800 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -700,3 +700,12 @@ bool string_in_list(const char *string, char **list, bool case_sensitive)
return false; } + +void safezero(void *data, size_t size) +{ + volatile uint8_t *p = data; + + while (size--) { + *p++ = 0; + } +} diff --git a/src/util/util.h b/src/util/util.h index 2d63e733f133f107d1ff44a049db1eb6eff09daa..72b8a23b8668dce6dcd7d5b2b8001f64eb76859d 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -541,6 +541,15 @@ errno_t add_string_to_list(TALLOC_CTX *mem_ctx, const char *string,
bool string_in_list(const char *string, char **list, bool case_sensitive);
+/** + * @brief Safely zero a segment of memory, + * prevents the compiler from optimizing out + * + * @param data The address of buffer to wipe + * @param s Size of the buffer + */ +void safezero(void *data, size_t size); + /* from sss_tc_utf8.c */ char * sss_tc_utf8_str_tolower(TALLOC_CTX *mem_ctx, const char *s);
These functions allow handling of auth tokens in a completely opaque way, with clear semantics and accessor fucntions that guarantee consistency, proper access to data and error conditions. --- Makefile.am | 2 + src/util/authtok.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/util/authtok.h | 180 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 377 insertions(+), 0 deletions(-) create mode 100644 src/util/authtok.c create mode 100644 src/util/authtok.h
diff --git a/Makefile.am b/Makefile.am index ce3f94f635f918438bf856c523e47c0f09fc328a..1e4442c4a4bdfafccf1db923d650da4d161ae480 100644 --- a/Makefile.am +++ b/Makefile.am @@ -369,6 +369,7 @@ dist_noinst_HEADERS = \ src/util/mmap_cache.h \ src/util/atomic_io.h \ src/util/auth_utils.h \ + src/util/authtok.h \ src/monitor/monitor.h \ src/monitor/monitor_interfaces.h \ src/responder/common/responder.h \ @@ -507,6 +508,7 @@ libsss_util_la_SOURCES = \ src/util/sss_tc_utf8.c \ src/util/murmurhash3.c \ src/util/atomic_io.c \ + src/util/authtok.c \ src/util/sss_selinux.c \ src/util/domain_info_utils.c \ src/util/util_lock.c diff --git a/src/util/authtok.c b/src/util/authtok.c new file mode 100644 index 0000000000000000000000000000000000000000..1f45953378021e9d30559030326134794965b240 --- /dev/null +++ b/src/util/authtok.c @@ -0,0 +1,195 @@ +/* + SSSD - auth utils + + Copyright (C) Simo Sorce simo@redhat.com 2012 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses/. +*/ + +#include "authtok.h" + +enum sss_authtok_type sss_authtok_get_type(struct sss_auth_token *tok) +{ + return tok->type; +} + +size_t sss_authtok_get_size(struct sss_auth_token *tok) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_PASSWORD: + case SSS_AUTHTOK_TYPE_CCFILE: + return tok->length; + default: + return 0; + } +} + +uint8_t *sss_authtok_get_data(struct sss_auth_token *tok) +{ + return (void *)tok->data; +} + +errno_t sss_authtok_get_password(struct sss_auth_token *tok, + const char **pwd, size_t *len) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_EMPTY: + return ENOENT; + case SSS_AUTHTOK_TYPE_PASSWORD: + *pwd = (const char *)tok->data; + if (len) { + *len = tok->length - 1; + } + return EOK; + default: + return EACCES; + } +} + +errno_t sss_authtok_get_ccfile(struct sss_auth_token *tok, + const char **ccfile, size_t *len) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_EMPTY: + return ENOENT; + case SSS_AUTHTOK_TYPE_CCFILE: + *ccfile = (const char *)tok->data; + if (len) { + *len = tok->length - 1; + } + return EOK; + default: + return EACCES; + } +} + +static errno_t sss_authtok_set_string(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + enum sss_authtok_type type, + const char *context_name, + const char *str, size_t len) +{ + size_t size; + + if (len == 0) { + len = strlen(str); + } else { + while (len > 0 && str[len - 1] == '\0') len--; + } + + if (len == 0) { + /* we do not allow zero length ttyped tokens */ + return EINVAL; + } + + size = len + 1; + + tok->data = talloc_named(mem_ctx, size, context_name); + if (!tok->data) { + return ENOMEM; + } + memcpy(tok->data, str, len); + tok->data[len] = '\0'; + tok->type = type; + tok->length = size; + + return EOK; + +} + +void sss_authtok_set_empty(struct sss_auth_token *tok) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_EMPTY: + return; + case SSS_AUTHTOK_TYPE_PASSWORD: + safezero(tok->data, tok->length); + default: + break; + } + + tok->type = SSS_AUTHTOK_TYPE_EMPTY; + talloc_zfree(tok->data); + tok->length = 0; +} + +errno_t sss_authtok_set_password(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *password, size_t len) +{ + sss_authtok_set_empty(tok); + + return sss_authtok_set_string(mem_ctx, tok, + SSS_AUTHTOK_TYPE_PASSWORD, + "password", password, len); +} + +errno_t sss_authtok_set_ccfile(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *ccfile, size_t len) +{ + sss_authtok_set_empty(tok); + + return sss_authtok_set_string(mem_ctx, tok, + SSS_AUTHTOK_TYPE_CCFILE, + "ccfile", ccfile, len); +} + +errno_t sss_authtok_set(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + enum sss_authtok_type type, + uint8_t *data, size_t len) +{ + switch (type) { + case SSS_AUTHTOK_TYPE_PASSWORD: + return sss_authtok_set_password(mem_ctx, tok, (const char *)data, len); + case SSS_AUTHTOK_TYPE_CCFILE: + return sss_authtok_set_ccfile(mem_ctx, tok, (const char *)data, len); + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + return EOK; + default: + return EINVAL; + } +} + +errno_t sss_authtok_copy(TALLOC_CTX *mem_ctx, + struct sss_auth_token *src, + struct sss_auth_token *dst) +{ + sss_authtok_set_empty(dst); + + if (src->type == SSS_AUTHTOK_TYPE_EMPTY) { + return EOK; + } + + dst->data = talloc_memdup(mem_ctx, src->data, src->length); + if (!dst->data) { + return ENOMEM; + } + dst->length = src->length; + dst->type = src->type; + + return EOK; +} + +void sss_authtok_wipe_password(struct sss_auth_token *tok) +{ + if (tok->type != SSS_AUTHTOK_TYPE_PASSWORD) { + return; + } + + safezero(tok->data, tok->length); +} + diff --git a/src/util/authtok.h b/src/util/authtok.h new file mode 100644 index 0000000000000000000000000000000000000000..c750711ea373506118aab75807dc706c217f6842 --- /dev/null +++ b/src/util/authtok.h @@ -0,0 +1,180 @@ +/* + SSSD - auth utils + + Copyright (C) Simo Sorce simo@redhat.com 2012 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses/. +*/ + +#ifndef __AUTHTOK_H__ +#define __AUTHTOK_H__ + +#include "util/util.h" +#include "sss_client/sss_cli.h" + +/* Auth token structure, + * please never use directly. + * Use ss_authtok_* accesor functions instead + */ +struct sss_auth_token { + enum sss_authtok_type type; + uint8_t *data; + size_t length; +}; + +/** + * @brief Returns the token type + * + * @param tok A pointer to an sss_auth_token + * + * @return A sss_authtok_type (empty, password, ...) + */ +enum sss_authtok_type sss_authtok_get_type(struct sss_auth_token *tok); + +/** + * @brief Returns the token size + * + * @param tok A pointer to an sss_auth_token + * + * @return The current size of the token payload + */ +size_t sss_authtok_get_size(struct sss_auth_token *tok); + +/** + * @brief Get the data buffer + * + * @param tok A pointer to an sss_auth_token + * + * @return A pointer to the token payload + */ +uint8_t *sss_authtok_get_data(struct sss_auth_token *tok); + +/** + * @brief Returns a const string if the auth token is of type + SSS_AUTHTOK_TYPE_PASSWORD, otherwise it returns an error + * + * @param tok A pointer to an sss_auth_token + * @param pwd A pointer to a const char *, that will point to a null + * terminated string + * @param len The length of the password string + * + * @return EOK on success + * ENOENT if the token is empty + * EACCESS if the token is not a password token + */ +errno_t sss_authtok_get_password(struct sss_auth_token *tok, + const char **pwd, size_t *len); + +/** + * @brief Set a password into a an auth token, replacing any previous data + * + * @param mem_ctx A memory context use to allocate the internal data + * @param tok A pointer to a sss_auth_token structure to change + * @param password A string + * @param len The length of the string or, if 0 is passed, + * then strlen(password) will be used internally. + * + * @return EOK on success + * ENOMEM on error + */ +errno_t sss_authtok_set_password(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *password, size_t len); + +/** + * @brief Returns a const string if the auth token is of type + SSS_AUTHTOK_TYPE_CCFILE, otherwise it returns an error + * + * @param tok A pointer to an sss_auth_token + * @param ccfile A pointer to a const char *, that will point to a null + * terminated string + * @param len The length of the string + * + * @return EOK on success + * ENOENT if the token is empty + * EACCESS if the token is not a password token + */ +errno_t sss_authtok_get_ccfile(struct sss_auth_token *tok, + const char **ccfile, size_t *len); + +/** + * @brief Set a cc file name into a an auth token, replacing any previous data + * + * @param mem_ctx A memory context use to allocate the internal data + * @param tok A pointer to a sss_auth_token structure to change + * @param ccfile A null terminated string + * @param len The length of the string + * + * @return EOK on success + * ENOMEM on error + */ +errno_t sss_authtok_set_ccfile(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *ccfile, size_t len); + +/** + * @brief Resets an auth token to the empty status + * + * @param tok A pointer to a sss_auth_token structure to reset + * + * NOTE: This function uses safezero() on the payload if the type + * is SSS_AUTHTOK_TYPE_PASSWORD + */ +void sss_authtok_set_empty(struct sss_auth_token *tok); + +/** + * @brief Set an auth token by type, replacing any previous data + * + * @param mem_ctx A memory context use to allocate the internal data + * @param tok A pointer to a sss_auth_token structure to change + * @param type A valid authtok type + * @param ccfile A data pointer + * @param len The length of the data + * + * @return EOK on success + * ENOMEM or EINVAL on error + */ +errno_t sss_authtok_set(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + enum sss_authtok_type type, + uint8_t *data, size_t len); + +/** + * @brief Copy an auth token from source to destination + * + * @param mem_ctx The memory context to use for allocations on dst + * @param src The source auth token + * @param dst The destination auth token + * + * @return EOK on success + * ENOMEM on error + */ +errno_t sss_authtok_copy(TALLOC_CTX *mem_ctx, + struct sss_auth_token *src, + struct sss_auth_token *dst); + +/** + * @brief Uses safezero to wipe the password from memory if the + * authtoken contains a password, otherwise does nothing. + * + * @param tok A pointer to a sss_auth_token structure to change + * + * NOTE: This function should only be used in destructors or similar + * functions where freing the actual string is unsafe and where it can + * be guaranteed that the auth token will not be used anymore. + * Use sss_authtok_set_empty() in normal circumstances. + */ +void sss_authtok_wipe_password(struct sss_auth_token *tok); + +#endif /* __AUTHTOK_H__ */
Use the new authtok abstraction and interfaces throught the code. --- Makefile.am | 2 + src/db/sysdb_ops.c | 1 - src/providers/data_provider.h | 9 +- src/providers/dp_auth_util.c | 76 +++++++---- src/providers/dp_pam_data_util.c | 113 ++++++++------- src/providers/ipa/ipa_auth.c | 6 +- src/providers/krb5/krb5_auth.c | 55 +++----- src/providers/krb5/krb5_child.c | 148 ++++++++++---------- src/providers/krb5/krb5_child_handler.c | 59 +++++++-- .../krb5/krb5_delayed_online_authentication.c | 50 +++++--- src/providers/krb5/krb5_renew_tgt.c | 18 +-- src/providers/ldap/ldap_auth.c | 90 +++++------- src/providers/ldap/sdap_async.c | 4 +- src/providers/ldap/sdap_async.h | 7 +- src/providers/ldap/sdap_async_connection.c | 88 +++++++----- src/providers/proxy/proxy.h | 7 +- src/providers/proxy/proxy_auth.c | 14 +- src/providers/proxy/proxy_child.c | 51 ++++--- src/responder/pam/pam_LOCAL_domain.c | 52 +++----- src/responder/pam/pamsrv_cmd.c | 134 ++++++++++-------- src/tests/krb5_child-test.c | 13 +- 21 files changed, 529 insertions(+), 468 deletions(-)
diff --git a/Makefile.am b/Makefile.am index 1e4442c4a4bdfafccf1db923d650da4d161ae480..06f6280913e0419210852872663f0220455cc909 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1446,6 +1446,7 @@ krb5_child_SOURCES = \ src/util/user_info_msg.c \ src/util/sss_krb5.c \ src/util/atomic_io.c \ + src/util/authtok.c \ src/util/util.c \ src/util/signal.c \ src/sss_client/common.c @@ -1467,6 +1468,7 @@ ldap_child_SOURCES = \ src/providers/ldap/ldap_child.c \ src/util/sss_krb5.c \ src/util/atomic_io.c \ + src/util/authtok.c \ src/util/util.c \ src/util/signal.c ldap_child_CFLAGS = \ diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c index b09f661c58ea8c3afb03556d084d5eb3b45e33a5..741dd63c441dbaa0693a12fe12706d83eeecc163 100644 --- a/src/db/sysdb_ops.c +++ b/src/db/sysdb_ops.c @@ -2691,7 +2691,6 @@ int sysdb_cache_auth(struct sysdb_ctx *sysdb, time_t expire_date = -1; time_t delayed_until = -1; int ret; - int i;
if (name == NULL || *name == '\0') { DEBUG(1, ("Missing user name.\n")); diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h index bb944509da9f1dc89216266cf62c57fb4127fd57..b370aa51dbe4015a26512a0f003defdb6851bf63 100644 --- a/src/providers/data_provider.h +++ b/src/providers/data_provider.h @@ -41,6 +41,7 @@ #include "sbus/sssd_dbus.h" #include "sbus/sbus_client.h" #include "sss_client/sss_cli.h" +#include "util/authtok.h"
#define DATA_PROVIDER_VERSION 0x0001 #define DATA_PROVIDER_PIPE "private/sbus-dp" @@ -162,18 +163,14 @@ struct response_data {
struct pam_data { int cmd; - uint32_t authtok_type; - uint32_t authtok_size; - uint32_t newauthtok_type; - uint32_t newauthtok_size; char *domain; char *user; char *service; char *tty; char *ruser; char *rhost; - uint8_t *authtok; - uint8_t *newauthtok; + struct sss_auth_token authtok; + struct sss_auth_token newauthtok; uint32_t cli_pid;
int pam_status; diff --git a/src/providers/dp_auth_util.c b/src/providers/dp_auth_util.c index 9a67564b78e558642f4116528d210251a0d9b5fd..54f0ee8ed6f1d537410a91f93e55316fc9b89886 100644 --- a/src/providers/dp_auth_util.c +++ b/src/providers/dp_auth_util.c @@ -24,30 +24,43 @@ bool dp_pack_pam_request(DBusMessage *msg, struct pam_data *pd) { dbus_bool_t db_ret; + const char *service; + const char *tty; + const char *ruser; + const char *rhost; + uint32_t authtok_type; + uint32_t authtok_length; + uint8_t *authtok_data; + uint32_t new_authtok_type; + uint32_t new_authtok_length; + uint8_t *new_authtok_data;
if (pd->user == NULL) return false; - if (pd->service == NULL) pd->service = talloc_strdup(pd, ""); - if (pd->tty == NULL) pd->tty = talloc_strdup(pd, ""); - if (pd->ruser == NULL) pd->ruser = talloc_strdup(pd, ""); - if (pd->rhost == NULL) pd->rhost = talloc_strdup(pd, ""); - + service = pd->service ? pd->service : ""; + tty = pd->tty ? pd->tty : ""; + ruser = pd->ruser ? pd->ruser : ""; + rhost = pd->rhost ? pd->rhost : ""; + authtok_type = (uint32_t)sss_authtok_get_type(&pd->authtok); + authtok_data = sss_authtok_get_data(&pd->authtok); + authtok_length = sss_authtok_get_size(&pd->authtok); + new_authtok_type = (uint32_t)sss_authtok_get_type(&pd->newauthtok); + new_authtok_data = sss_authtok_get_data(&pd->newauthtok); + new_authtok_length = sss_authtok_get_size(&pd->newauthtok);
db_ret = dbus_message_append_args(msg, DBUS_TYPE_INT32, &(pd->cmd), DBUS_TYPE_STRING, &(pd->user), DBUS_TYPE_STRING, &(pd->domain), - DBUS_TYPE_STRING, &(pd->service), - DBUS_TYPE_STRING, &(pd->tty), - DBUS_TYPE_STRING, &(pd->ruser), - DBUS_TYPE_STRING, &(pd->rhost), - DBUS_TYPE_UINT32, &(pd->authtok_type), + DBUS_TYPE_STRING, &service, + DBUS_TYPE_STRING, &tty, + DBUS_TYPE_STRING, &ruser, + DBUS_TYPE_STRING, &rhost, + DBUS_TYPE_UINT32, &authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd->authtok), - (pd->authtok_size), - DBUS_TYPE_UINT32, &(pd->newauthtok_type), + &authtok_data, authtok_length, + DBUS_TYPE_UINT32, &new_authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd->newauthtok), - pd->newauthtok_size, + &new_authtok_data, new_authtok_length, DBUS_TYPE_INT32, &(pd->priv), DBUS_TYPE_UINT32, &(pd->cli_pid), DBUS_TYPE_INVALID); @@ -61,6 +74,12 @@ bool dp_unpack_pam_request(DBusMessage *msg, TALLOC_CTX *mem_ctx, dbus_bool_t db_ret; int ret; struct pam_data pd; + uint32_t authtok_type; + uint32_t authtok_length; + uint8_t *authtok_data; + uint32_t new_authtok_type; + uint32_t new_authtok_length; + uint8_t *new_authtok_data;
memset(&pd, 0, sizeof(pd));
@@ -72,14 +91,12 @@ bool dp_unpack_pam_request(DBusMessage *msg, TALLOC_CTX *mem_ctx, DBUS_TYPE_STRING, &(pd.tty), DBUS_TYPE_STRING, &(pd.ruser), DBUS_TYPE_STRING, &(pd.rhost), - DBUS_TYPE_UINT32, &(pd.authtok_type), + DBUS_TYPE_UINT32, &authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd.authtok), - &(pd.authtok_size), - DBUS_TYPE_UINT32, &(pd.newauthtok_type), + &authtok_data, &authtok_length, + DBUS_TYPE_UINT32, &new_authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd.newauthtok), - &(pd.newauthtok_size), + &new_authtok_data, &new_authtok_length, DBUS_TYPE_INT32, &(pd.priv), DBUS_TYPE_UINT32, &(pd.cli_pid), DBUS_TYPE_INVALID); @@ -95,14 +112,17 @@ bool dp_unpack_pam_request(DBusMessage *msg, TALLOC_CTX *mem_ctx, return false; }
- if (pd.authtok_size != 0 && pd.authtok != NULL) { - memset(pd.authtok, 0, pd.authtok_size); - pd.authtok_size = 0; + ret = sss_authtok_set(*new_pd, &((*new_pd)->authtok), authtok_type, + authtok_data, authtok_length); + if (ret) { + DEBUG(1, ("Failed to set auth token: %d [%s]\n", ret, strerror(ret))); + return false; } - - if (pd.newauthtok_size != 0 && pd.newauthtok != NULL) { - memset(pd.newauthtok, 0, pd.newauthtok_size); - pd.newauthtok_size = 0; + ret = sss_authtok_set(*new_pd, &((*new_pd)->newauthtok), new_authtok_type, + new_authtok_data, new_authtok_length); + if (ret) { + DEBUG(1, ("Failed to set auth token: %d [%s]\n", ret, strerror(ret))); + return false; }
return true; diff --git a/src/providers/dp_pam_data_util.c b/src/providers/dp_pam_data_util.c index 889c47f00bfb49effab982ed40454b5120b84bf6..64f0d69bd0e8ebc28df958c393b40afcb5e18c31 100644 --- a/src/providers/dp_pam_data_util.c +++ b/src/providers/dp_pam_data_util.c @@ -25,26 +25,6 @@ #include "providers/data_provider.h"
-#define PD_STR_COPY(el) do { \ - if (old_pd->el != NULL) { \ - pd->el = talloc_strdup(pd, old_pd->el); \ - if (pd->el == NULL) { \ - DEBUG(1, ("talloc_strdup failed.\n")); \ - goto failed; \ - } \ - } \ -} while(0) - -#define PD_MEM_COPY(el, size) do { \ - if (old_pd->el != NULL) { \ - pd->el = talloc_memdup(pd, old_pd->el, (size)); \ - if (pd->el == NULL) { \ - DEBUG(1, ("talloc_memdup failed.\n")); \ - goto failed; \ - } \ - } \ -} while(0) - #define PAM_SAFE_ITEM(item) item ? item : "not set"
static const char *pamcmd2str(int cmd) { @@ -72,17 +52,11 @@ int pam_data_destructor(void *ptr) { struct pam_data *pd = talloc_get_type(ptr, struct pam_data);
- if (pd->authtok_size != 0 && pd->authtok != NULL) { - memset(pd->authtok, 0, pd->authtok_size); - pd->authtok_size = 0; - } + /* make sure to wipe any password from memory before freeing */ + sss_authtok_wipe_password(&pd->authtok); + sss_authtok_wipe_password(&pd->newauthtok);
- if (pd->newauthtok_size != 0 && pd->newauthtok != NULL) { - memset(pd->newauthtok, 0, pd->newauthtok_size); - pd->newauthtok_size = 0; - } - - return EOK; + return 0; }
struct pam_data *create_pam_data(TALLOC_CTX *mem_ctx) @@ -100,41 +74,72 @@ struct pam_data *create_pam_data(TALLOC_CTX *mem_ctx) return pd; }
-errno_t copy_pam_data(TALLOC_CTX *mem_ctx, struct pam_data *old_pd, - struct pam_data **new_pd) +errno_t copy_pam_data(TALLOC_CTX *mem_ctx, struct pam_data *src, + struct pam_data **dst) { struct pam_data *pd = NULL; + errno_t ret;
pd = create_pam_data(mem_ctx); if (pd == NULL) { - DEBUG(1, ("create_pam_data failed.\n")); - return ENOMEM; + ret = ENOMEM; + goto failed; }
- pd->cmd = old_pd->cmd; - pd->authtok_type = old_pd->authtok_type; - pd->authtok_size = old_pd->authtok_size; - pd->newauthtok_type = old_pd->newauthtok_type; - pd->newauthtok_size = old_pd->newauthtok_size; - pd->priv = old_pd->priv; + pd->cmd = src->cmd; + pd->priv = src->priv;
- PD_STR_COPY(domain); - PD_STR_COPY(user); - PD_STR_COPY(service); - PD_STR_COPY(tty); - PD_STR_COPY(ruser); - PD_STR_COPY(rhost); - PD_MEM_COPY(authtok, old_pd->authtok_size); - PD_MEM_COPY(newauthtok, old_pd->newauthtok_size); - pd->cli_pid = old_pd->cli_pid; + pd->domain = talloc_strdup(pd, src->domain); + if (pd->domain == NULL && src->domain != NULL) { + ret = ENOMEM; + goto failed; + } + pd->user = talloc_strdup(pd, src->user); + if (pd->user == NULL && src->user != NULL) { + ret = ENOMEM; + goto failed; + } + pd->service = talloc_strdup(pd, src->service); + if (pd->service == NULL && src->service != NULL) { + ret = ENOMEM; + goto failed; + } + pd->tty = talloc_strdup(pd, src->tty); + if (pd->tty == NULL && src->tty != NULL) { + ret = ENOMEM; + goto failed; + } + pd->ruser = talloc_strdup(pd, src->ruser); + if (pd->ruser == NULL && src->ruser != NULL) { + ret = ENOMEM; + goto failed; + } + pd->rhost = talloc_strdup(pd, src->rhost); + if (pd->rhost == NULL && src->rhost != NULL) { + ret = ENOMEM; + goto failed; + } + + pd->cli_pid = src->cli_pid; + + ret = sss_authtok_copy(pd, &src->authtok, &pd->authtok); + if (ret) { + goto failed; + } + + ret = sss_authtok_copy(pd, &src->newauthtok, &pd->newauthtok); + if (ret) { + goto failed; + }
- *new_pd = pd; + *dst = pd;
return EOK;
failed: talloc_free(pd); - return ENOMEM; + DEBUG(1, ("copy_pam_data failed: (%d) %s.\n", ret, strerror(ret))); + return ret; }
void pam_print_data(int l, struct pam_data *pd) @@ -146,10 +151,8 @@ void pam_print_data(int l, struct pam_data *pd) DEBUG(l, ("tty: %s\n", PAM_SAFE_ITEM(pd->tty))); DEBUG(l, ("ruser: %s\n", PAM_SAFE_ITEM(pd->ruser))); DEBUG(l, ("rhost: %s\n", PAM_SAFE_ITEM(pd->rhost))); - DEBUG(l, ("authtok type: %d\n", pd->authtok_type)); - DEBUG(l, ("authtok size: %d\n", pd->authtok_size)); - DEBUG(l, ("newauthtok type: %d\n", pd->newauthtok_type)); - DEBUG(l, ("newauthtok size: %d\n", pd->newauthtok_size)); + DEBUG(l, ("authtok type: %d\n", sss_authtok_get_type(&pd->authtok))); + DEBUG(l, ("newauthtok type: %d\n", sss_authtok_get_type(&pd->newauthtok))); DEBUG(l, ("priv: %d\n", pd->priv)); DEBUG(l, ("cli_pid: %d\n", pd->cli_pid)); } diff --git a/src/providers/ipa/ipa_auth.c b/src/providers/ipa/ipa_auth.c index eb62f0295cc0dc36daad9d4147556d993c7f1509..ee15afa5c83c0c68d19e169649ae6958a1553bd1 100644 --- a/src/providers/ipa/ipa_auth.c +++ b/src/providers/ipa/ipa_auth.c @@ -332,7 +332,6 @@ static void ipa_migration_flag_connect_done(struct tevent_req *req) const char **attrs; struct ldb_message *user_msg; const char *dn; - struct dp_opt_blob password; int dp_err = DP_ERR_FATAL; int ret;
@@ -374,11 +373,8 @@ static void ipa_migration_flag_connect_done(struct tevent_req *req) goto done; }
- password.data = state->pd->authtok; - password.length = state->pd->authtok_size; - req = sdap_auth_send(state, state->ev, state->sh, NULL, NULL, dn, - "password", password); + &state->pd->authtok); if (req == NULL) { DEBUG(SSSDBG_OP_FAILURE, ("sdap_auth_send failed.\n")); goto done; diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c index 559ad583587ee0490bf9f9614647826d18a94762..87ec05f533996080c725430a5913d398daa0e594 100644 --- a/src/providers/krb5/krb5_auth.c +++ b/src/providers/krb5/krb5_auth.c @@ -278,12 +278,12 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, struct pam_data *pd, uid_t uid, int *pam_status, int *dp_err) { - char *password = NULL; + const char *password = NULL; errno_t ret;
- password = talloc_strndup(state, pd->authtok, pd->authtok_size); - if (!password) { - DEBUG(0, ("Out of memory copying password\n")); + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + if (ret != EOK) { + DEBUG(0, ("Failed to get password [%d] %s\n", ret, strerror(ret))); *pam_status = PAM_SYSTEM_ERR; *dp_err = DP_ERR_OK; return; @@ -294,7 +294,7 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, DEBUG(1, ("Offline authentication failed\n")); *pam_status = cached_login_pam_status(ret); *dp_err = DP_ERR_OK; - goto done; + return; }
ret = add_user_to_delayed_online_authentication(krb5_ctx, pd, uid); @@ -304,12 +304,6 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, } *pam_status = PAM_AUTHINFO_UNAVAIL; *dp_err = DP_ERR_OFFLINE; - -done: - if (password) { - for (i = 0; password[i]; i++) password[i] = 0; - talloc_zfree(password); - } }
static errno_t krb5_auth_prepare_ccache_file(struct krb5child_req *kr, @@ -388,16 +382,9 @@ static errno_t krb5_auth_prepare_ccache_file(struct krb5child_req *kr,
static void krb5_auth_store_creds(struct sysdb_ctx *sysdb, struct pam_data *pd) { - TALLOC_CTX *tmp_ctx; char *password = NULL; int ret = EOK;
- tmp_ctx = talloc_new(NULL); - if (!tmp_ctx) { - DEBUG(0, ("Out of memory when trying to store credentials\n")); - return; - } - switch(pd->cmd) { case SSS_CMD_RENEW: /* The authtok is set to the credential cache @@ -407,23 +394,21 @@ static void krb5_auth_store_creds(struct sysdb_ctx *sysdb, struct pam_data *pd) break; case SSS_PAM_AUTHENTICATE: case SSS_PAM_CHAUTHTOK_PRELIM: - password = talloc_size(tmp_ctx, pd->authtok_size + 1); - if (password != NULL) { - memcpy(password, pd->authtok, pd->authtok_size); - password[pd->authtok_size] = '\0'; - } + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); break; case SSS_PAM_CHAUTHTOK: - password = talloc_size(tmp_ctx, pd->newauthtok_size + 1); - if (password != NULL) { - memcpy(password, pd->newauthtok, pd->newauthtok_size); - password[pd->newauthtok_size] = '\0'; - } + ret = sss_authtok_get_password(&pd->newauthtok, &password, NULL); break; default: DEBUG(0, ("unsupported PAM command [%d].\n", pd->cmd)); }
+ if (ret != EOK) { + DEBUG(0, ("Failed to get password [%d] %s\n", ret, strerror(ret))); + /* password caching failures are not fatal errors */ + return; + } + if (password == NULL) { if (pd->cmd != SSS_CMD_RENEW) { DEBUG(0, ("password not available, offline auth may not work.\n")); @@ -432,16 +417,12 @@ static void krb5_auth_store_creds(struct sysdb_ctx *sysdb, struct pam_data *pd) return; }
- talloc_set_destructor((TALLOC_CTX *)password, password_destructor); - ret = sysdb_cache_password(sysdb, pd->user, password); if (ret) { DEBUG(2, ("Failed to cache password, offline auth may not work." " (%d)[%s]!?\n", ret, strerror(ret))); /* password caching failures are not fatal errors */ } - - talloc_zfree(tmp_ctx); }
/* krb5_auth request */ @@ -506,9 +487,17 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx, case SSS_PAM_AUTHENTICATE: case SSS_CMD_RENEW: case SSS_PAM_CHAUTHTOK: + if (sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { + DEBUG(1, ("Missing authtok for user [%s].\n", pd->user)); + state->pam_status = PAM_SYSTEM_ERR; + state->dp_err = DP_ERR_FATAL; + ret = EINVAL; + goto done; + } break; case SSS_PAM_CHAUTHTOK_PRELIM: - if (pd->priv == 1 && pd->authtok_size == 0) { + if (pd->priv == 1 && + sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { DEBUG(4, ("Password reset by root is not supported.\n")); state->pam_status = PAM_PERM_DENIED; state->dp_err = DP_ERR_OK; diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c index 66e22f4330642189370e420d0c15bce56ca537fa..d1a42d56f1cb7137f2e21b54f6959da2fec5f6d0 100644 --- a/src/providers/krb5/krb5_child.c +++ b/src/providers/krb5/krb5_child.c @@ -950,7 +950,7 @@ done: }
static krb5_error_code get_and_save_tgt(struct krb5_req *kr, - char *password) + const char *password) { krb5_error_code kerr = 0; int ret; @@ -971,7 +971,8 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr, DEBUG(SSSDBG_TRACE_FUNC, ("Attempting kinit for realm [%s]\n",realm_name)); kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - password, sss_krb5_prompter, kr, 0, + discard_const(password), + sss_krb5_prompter, kr, 0, NULL, kr->options); if (kerr != 0) { KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); @@ -1066,8 +1067,8 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) { int ret; krb5_error_code kerr = 0; - char *pass_str = NULL; - char *newpass_str = NULL; + const char *password = NULL; + const char *newpassword = NULL; int pam_status = PAM_SYSTEM_ERR; int result_code = -1; krb5_data result_code_string; @@ -1082,20 +1083,15 @@ static errno_t changepw_child(int fd, struct krb5_req *kr)
DEBUG(SSSDBG_TRACE_LIBS, ("Password change operation\n"));
- if (kr->pd->authtok_type != SSS_AUTHTOK_TYPE_PASSWORD) { + ret = sss_authtok_get_password(&kr->pd->authtok, &password, NULL); + if (ret != EOK) { + DEBUG(1, ("Failed to fetch current password [%d] %s.\n", + ret, strerror(ret))); pam_status = PAM_CRED_INSUFFICIENT; kerr = KRB5KRB_ERR_GENERIC; goto sendresponse; }
- pass_str = talloc_strndup(kr, (const char *) kr->pd->authtok, - kr->pd->authtok_size); - if (pass_str == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - kerr = KRB5KRB_ERR_GENERIC; - goto sendresponse; - } - if (kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) { /* We do not need a password expiration warning here. */ prompter = NULL; @@ -1112,7 +1108,8 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) DEBUG(SSSDBG_TRACE_FUNC, ("Attempting kinit for realm [%s]\n",realm_name)); kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - pass_str, prompter, kr, 0, + discard_const(password), + prompter, kr, 0, SSSD_KRB5_CHANGEPW_PRINCIPAL, chagepw_options); sss_krb5_get_init_creds_opt_free(kr->ctx, chagepw_options); @@ -1121,9 +1118,7 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) goto sendresponse; }
- memset(pass_str, 0, kr->pd->authtok_size); - talloc_zfree(pass_str); - memset(kr->pd->authtok, 0, kr->pd->authtok_size); + sss_authtok_set_empty(&kr->pd->authtok);
if (kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) { DEBUG(SSSDBG_TRACE_LIBS, @@ -1134,17 +1129,18 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) goto sendresponse; }
- newpass_str = talloc_strndup(kr, (const char *) kr->pd->newauthtok, - kr->pd->newauthtok_size); - if (newpass_str == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); + ret = sss_authtok_get_password(&kr->pd->newauthtok, &newpassword, NULL); + if (ret != EOK) { + DEBUG(1, ("Failed to fetch new password [%d] %s.\n", + ret, strerror(ret))); kerr = KRB5KRB_ERR_GENERIC; goto sendresponse; }
memset(&result_code_string, 0, sizeof(krb5_data)); memset(&result_string, 0, sizeof(krb5_data)); - kerr = krb5_change_password(kr->ctx, kr->creds, newpass_str, &result_code, + kerr = krb5_change_password(kr->ctx, kr->creds, + discard_const(newpassword), &result_code, &result_code_string, &result_string);
if (kerr == KRB5_KDC_UNREACH) { @@ -1200,10 +1196,9 @@ static errno_t changepw_child(int fd, struct krb5_req *kr)
krb5_free_cred_contents(kr->ctx, kr->creds);
- kerr = get_and_save_tgt(kr, newpass_str); - memset(newpass_str, 0, kr->pd->newauthtok_size); - talloc_zfree(newpass_str); - memset(kr->pd->newauthtok, 0, kr->pd->newauthtok_size); + kerr = get_and_save_tgt(kr, newpassword); + + sss_authtok_set_empty(&kr->pd->newauthtok);
pam_status = kerr_to_status(kerr);
@@ -1220,28 +1215,21 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) { int ret; krb5_error_code kerr = 0; - char *pass_str = NULL; + const char *password = NULL; int pam_status = PAM_SYSTEM_ERR; krb5_get_init_creds_opt *chagepw_options;
DEBUG(SSSDBG_TRACE_LIBS, ("Attempting to get a TGT\n"));
- if (kr->pd->authtok_type != SSS_AUTHTOK_TYPE_PASSWORD) { + ret = sss_authtok_get_password(&kr->pd->authtok, &password, NULL); + if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Unknown authtok type\n")); pam_status = PAM_CRED_INSUFFICIENT; kerr = KRB5KRB_ERR_GENERIC; goto sendresponse; }
- pass_str = talloc_strndup(kr, (const char *) kr->pd->authtok, - kr->pd->authtok_size); - if (pass_str == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - kerr = KRB5KRB_ERR_GENERIC; - goto sendresponse; - } - - kerr = get_and_save_tgt(kr, pass_str); + kerr = get_and_save_tgt(kr, password);
/* If the password is expired the KDC will always return KRB5KDC_ERR_KEY_EXP regardless if the supplied password is correct or @@ -1264,7 +1252,8 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) }
kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - pass_str, sss_krb5_prompter, kr, 0, + discard_const(password), + sss_krb5_prompter, kr, 0, SSSD_KRB5_CHANGEPW_PRINCIPAL, chagepw_options);
@@ -1276,9 +1265,7 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) } }
- memset(pass_str, 0, kr->pd->authtok_size); - talloc_zfree(pass_str); - memset(kr->pd->authtok, 0, kr->pd->authtok_size); + sss_authtok_set_empty(&kr->pd->authtok);
pam_status = kerr_to_status(kerr);
@@ -1333,25 +1320,20 @@ static errno_t renew_tgt_child(int fd, struct krb5_req *kr) int ret; int status = PAM_AUTHTOK_ERR; int kerr; - char *ccname; + const char *ccname; krb5_ccache ccache = NULL;
DEBUG(SSSDBG_TRACE_LIBS, ("Renewing a ticket\n"));
- if (kr->pd->authtok_type != SSS_AUTHTOK_TYPE_CCFILE) { - DEBUG(1, ("Unsupported authtok type for TGT renewal [%d].\n", - kr->pd->authtok_type)); + ret = sss_authtok_get_ccfile(&kr->pd->authtok, &ccname, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + ("Unsupported authtok type for TGT renewal [%d].\n", + sss_authtok_get_type(&kr->pd->authtok))); kerr = EINVAL; goto done; }
- ccname = talloc_strndup(kr, (char *) kr->pd->authtok, kr->pd->authtok_size); - if (ccname == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - kerr = ENOMEM; - goto done; - } - kerr = krb5_cc_resolve(kr->ctx, ccname, &ccache); if (kerr != 0) { KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); @@ -1444,6 +1426,38 @@ static errno_t create_empty_ccache(int fd, struct krb5_req *kr) return ret; }
+static errno_t unpack_authtok(TALLOC_CTX *mem_ctx, struct sss_auth_token *tok, + uint8_t *buf, size_t size, size_t *p) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + errno_t ret = EOK; + + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, buf + *p, size, p); + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_length, buf + *p, size, p); + if ((*p + auth_token_length) > size) { + return EINVAL; + } + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_set_password(mem_ctx, tok, (char *)(buf + *p), 0); + break; + case SSS_AUTHTOK_TYPE_CCFILE: + ret = sss_authtok_set_ccfile(mem_ctx, tok, (char *)(buf + *p), 0); + break; + default: + return EINVAL; + } + + if (ret == EOK) { + *p += auth_token_length; + } + return ret; +} + static errno_t unpack_buffer(uint8_t *buf, size_t size, struct pam_data *pd, struct krb5_req *kr, uint32_t *offline) { @@ -1451,6 +1465,7 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size, struct pam_data *pd, uint32_t len; uint32_t validate; uint32_t different_realm; + errno_t ret;
DEBUG(SSSDBG_TRACE_LIBS, ("total buffer size: [%d]\n", size));
@@ -1491,35 +1506,26 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size, struct pam_data *pd, if (kr->keytab == NULL) return ENOMEM; p += len;
- SAFEALIGN_COPY_UINT32_CHECK(&pd->authtok_type, buf + p, size, &p); - SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p); - if ((p + len) > size) return EINVAL; - pd->authtok = (uint8_t *)talloc_strndup(pd, (char *)(buf + p), len); - if (pd->authtok == NULL) return ENOMEM; - pd->authtok_size = len + 1; - p += len; + ret = unpack_authtok(pd, &pd->authtok, buf, size, &p); + if (ret) { + return ret; + }
DEBUG(SSSDBG_CONF_SETTINGS, ("ccname: [%s] keytab: [%s]\n", kr->ccname, kr->keytab)); } else { kr->ccname = NULL; kr->keytab = NULL; - pd->authtok = NULL; - pd->authtok_size = 0; + sss_authtok_set_empty(&pd->authtok); }
if (pd->cmd == SSS_PAM_CHAUTHTOK) { - SAFEALIGN_COPY_UINT32_CHECK(&pd->newauthtok_type, buf + p, size, &p); - SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p); - - if ((p + len) > size) return EINVAL; - pd->newauthtok = (uint8_t *)talloc_strndup(pd, (char *)(buf + p), len); - if (pd->newauthtok == NULL) return ENOMEM; - pd->newauthtok_size = len + 1; - p += len; + ret = unpack_authtok(pd, &pd->newauthtok, buf, size, &p); + if (ret) { + return ret; + } } else { - pd->newauthtok = NULL; - pd->newauthtok_size = 0; + sss_authtok_set_empty(&pd->newauthtok); }
if (pd->cmd == SSS_PAM_ACCT_MGMT) { diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c index e792db3f7a6ebe7857b1ec699bc37d52ae3cad5d..5adbcf700ebf02a2aa524af3cecab51e543b4986 100644 --- a/src/providers/krb5/krb5_child_handler.c +++ b/src/providers/krb5/krb5_child_handler.c @@ -85,6 +85,43 @@ static int child_io_destructor(void *ptr) return EOK; }
+static errno_t pack_authtok(struct io_buffer *buf, size_t *rp, + struct sss_auth_token *tok) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + const char *data; + size_t len; + errno_t ret = EOK; + + auth_token_type = sss_authtok_get_type(tok); + + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + auth_token_length = 0; + data = ""; + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_get_password(tok, &data, &len); + auth_token_length = len + 1; + break; + case SSS_AUTHTOK_TYPE_CCFILE: + ret = sss_authtok_get_password(tok, &data, &len); + auth_token_length = len + 1; + break; + default: + ret = EINVAL; + } + + if (ret == EOK) { + SAFEALIGN_COPY_UINT32(&buf->data[*rp], &auth_token_type, rp); + SAFEALIGN_COPY_UINT32(&buf->data[*rp], &auth_token_length, rp); + safealign_memcpy(&buf->data[*rp], data, auth_token_length, rp); + } + + return ret; +} + static errno_t create_send_buffer(struct krb5child_req *kr, struct io_buffer **io_buf) { @@ -94,6 +131,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr, uint32_t validate; uint32_t different_realm; size_t username_len = 0; + errno_t ret;
keytab = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_KEYTAB); if (keytab == NULL) { @@ -117,11 +155,12 @@ static errno_t create_send_buffer(struct krb5child_req *kr, kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM || kr->pd->cmd == SSS_PAM_CHAUTHTOK) { buf->size += 4*sizeof(uint32_t) + strlen(kr->ccname) + strlen(keytab) + - kr->pd->authtok_size; + sss_authtok_get_size(&kr->pd->authtok); }
if (kr->pd->cmd == SSS_PAM_CHAUTHTOK) { - buf->size += 2*sizeof(uint32_t) + kr->pd->newauthtok_size; + buf->size += 2*sizeof(uint32_t) + + sss_authtok_get_size(&kr->pd->newauthtok); }
if (kr->pd->cmd == SSS_PAM_ACCT_MGMT) { @@ -157,17 +196,17 @@ static errno_t create_send_buffer(struct krb5child_req *kr, SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(keytab), &rp); safealign_memcpy(&buf->data[rp], keytab, strlen(keytab), &rp);
- SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->authtok_type, &rp); - SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->authtok_size, &rp); - safealign_memcpy(&buf->data[rp], kr->pd->authtok, - kr->pd->authtok_size, &rp); + ret = pack_authtok(buf, &rp, &kr->pd->authtok); + if (ret) { + return ret; + } }
if (kr->pd->cmd == SSS_PAM_CHAUTHTOK) { - SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->newauthtok_type, &rp); - SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->newauthtok_size, &rp); - safealign_memcpy(&buf->data[rp], kr->pd->newauthtok, - kr->pd->newauthtok_size, &rp); + ret = pack_authtok(buf, &rp, &kr->pd->newauthtok); + if (ret) { + return ret; + } }
if (kr->pd->cmd == SSS_PAM_ACCT_MGMT) { diff --git a/src/providers/krb5/krb5_delayed_online_authentication.c b/src/providers/krb5/krb5_delayed_online_authentication.c index d5dea3bb4c7661f45b6bea83cf803c7d681062cc..f95fa634c34ebee37bffb785abe4ef5b35318a82 100644 --- a/src/providers/krb5/krb5_delayed_online_authentication.c +++ b/src/providers/krb5/krb5_delayed_online_authentication.c @@ -71,27 +71,29 @@ static void authenticate_user(struct tevent_context *ev,
DEBUG_PAM_DATA(9, pd);
- if (pd->authtok == NULL || pd->authtok_size == 0) { - DEBUG(1, ("Missing authtok for user [%s].\n", pd->user)); - return; - } - #ifdef USE_KEYRING + char *password; long keysize; long keyrevoke; - int ret; - keysize = keyctl_read(pd->key_serial, (char *) pd->authtok, - pd->authtok_size); - keyrevoke = keyctl_revoke(pd->key_serial); + errno_t ret; + + keysize = keyctl_read_alloc(pd->key_serial, (void **)&password); if (keysize == -1) { ret = errno; DEBUG(1, ("keyctl_read failed [%d][%s].\n", ret, strerror(ret))); return; - } else if (keysize != pd->authtok_size) { - DEBUG(1, ("keyctl_read returned key with wrong size, " - "expect [%d] got [%d].\n", pd->authtok_size, keysize)); + } + + ret = sss_authtok_set_password(pd, &pd->authtok, password, keysize); + safezero(password, keysize); + free(password); + if (ret) { + DEBUG(1, ("failed to set password in auth token [%d][%s].\n", + ret, strerror(ret))); return; } + + keyrevoke = keyctl_revoke(pd->key_serial); if (keyrevoke == -1) { ret = errno; DEBUG(1, ("keyctl_revoke failed [%d][%s].\n", ret, strerror(ret))); @@ -244,8 +246,8 @@ errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx, return EINVAL; }
- if (pd->authtok_size == 0 || pd->authtok == NULL) { - DEBUG(1, ("Missing authtok for user [%s].\n", pd->user)); + if (sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { + DEBUG(1, ("Invalid authtok for user [%s].\n", pd->user)); return EINVAL; }
@@ -257,17 +259,29 @@ errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx,
#ifdef USE_KEYRING - new_pd->key_serial = add_key("user", new_pd->user, new_pd->authtok, - new_pd->authtok_size, KEY_SPEC_SESSION_KEYRING); + const char *password; + size_t len; + + ret = sss_authtok_get_password(&new_pd->authtok, &password, &len); + if (ret) { + DEBUG(1, ("Failed to get password [%d][%s].\n", ret, strerror(ret))); + sss_authtok_set_empty(&new_pd->authtok); + talloc_free(new_pd); + return ret; + } + + new_pd->key_serial = add_key("user", new_pd->user, password, len, + KEY_SPEC_SESSION_KEYRING); if (new_pd->key_serial == -1) { ret = errno; - DEBUG(1, ("add_key fialed [%d][%s].\n", ret, strerror(ret))); + DEBUG(1, ("add_key failed [%d][%s].\n", ret, strerror(ret))); + sss_authtok_set_empty(&new_pd->authtok); talloc_free(new_pd); return ret; } DEBUG(9, ("Saved authtok of user [%s] with serial [%ld].\n", new_pd->user, new_pd->key_serial)); - memset(new_pd->authtok, 0, new_pd->authtok_size); + sss_authtok_set_empty(&new_pd->authtok); #endif
key.type = HASH_KEY_ULONG; diff --git a/src/providers/krb5/krb5_renew_tgt.c b/src/providers/krb5/krb5_renew_tgt.c index ccb7e6af6d05121292d1152977c319daf660c9ef..4a812ab04d028961914557522423be82a1a01941 100644 --- a/src/providers/krb5/krb5_renew_tgt.c +++ b/src/providers/krb5/krb5_renew_tgt.c @@ -593,22 +593,14 @@ errno_t add_tgt_to_renew_table(struct krb5_ctx *krb5_ctx, const char *ccfile, goto done; }
- if (renew_data->pd->newauthtok_type != SSS_AUTHTOK_TYPE_EMPTY) { - talloc_zfree(renew_data->pd->newauthtok); - renew_data->pd->newauthtok_size = 0; - renew_data->pd->newauthtok_type = SSS_AUTHTOK_TYPE_EMPTY; - } + sss_authtok_set_empty(&renew_data->pd->newauthtok);
- talloc_zfree(renew_data->pd->authtok); - renew_data->pd->authtok = (uint8_t *) talloc_strdup(renew_data->pd, - renew_data->ccfile); - if (renew_data->pd->authtok == NULL) { - DEBUG(1, ("talloc_strdup failed.\n")); - ret = ENOMEM; + ret = sss_authtok_set_ccfile(renew_data->pd, &renew_data->pd->authtok, + renew_data->ccfile, 0); + if (ret) { + DEBUG(1, ("Failed to store ccfile in auth token.\n")); goto done; } - renew_data->pd->authtok_size = strlen((char *) renew_data->pd->authtok) + 1; - renew_data->pd->authtok_type = SSS_AUTHTOK_TYPE_CCFILE;
renew_data->pd->cmd = SSS_CMD_RENEW;
diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c index 32a2e04ea959a3cc81b88f5b2b19575c813e8adf..98483fee0da418523e78152861d489988eb9c6c2 100644 --- a/src/providers/ldap/ldap_auth.c +++ b/src/providers/ldap/ldap_auth.c @@ -462,7 +462,7 @@ struct auth_state { struct tevent_context *ev; struct sdap_auth_ctx *ctx; const char *username; - struct dp_opt_blob password; + struct sss_auth_token *authtok; struct sdap_service *sdap_service;
struct sdap_handle *sh; @@ -484,7 +484,7 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx, struct tevent_context *ev, struct sdap_auth_ctx *ctx, const char *username, - struct dp_opt_blob password, + struct sss_auth_token *authtok, bool try_chpass_service) { struct tevent_req *req; @@ -493,8 +493,8 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx, req = tevent_req_create(memctx, &state, struct auth_state); if (!req) return NULL;
- /* Treat a zero-length password as a failure */ - if (password.length == 0) { + /* The token must be a password token */ + if (sss_authtok_get_type(authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { state->result = SDAP_AUTH_FAILED; tevent_req_done(req); return tevent_req_post(req, ev); @@ -503,7 +503,7 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx, state->ev = ev; state->ctx = ctx; state->username = username; - state->password = password; + state->authtok = authtok; state->srv = NULL; if (try_chpass_service && ctx->chpass_service != NULL && ctx->chpass_service->name != NULL) { @@ -632,7 +632,7 @@ static void auth_connect_done(struct tevent_req *subreq)
subreq = sdap_auth_send(state, state->ev, state->sh, NULL, NULL, state->dn, - "password", state->password); + state->authtok); if (!subreq) { tevent_req_error(req, ENOMEM); return; @@ -727,8 +727,6 @@ struct sdap_pam_chpass_state { struct pam_data *pd; const char *username; char *dn; - char *password; - char *new_password; struct sdap_handle *sh;
struct sdap_auth_ctx *ctx; @@ -744,7 +742,6 @@ void sdap_pam_chpass_handler(struct be_req *breq) struct sdap_auth_ctx *ctx; struct tevent_req *subreq; struct pam_data *pd; - struct dp_opt_blob authtok; int dp_err = DP_ERR_FATAL;
ctx = talloc_get_type(breq->be_ctx->bet_info[BET_CHPASS].pvt_bet_data, @@ -758,8 +755,8 @@ void sdap_pam_chpass_handler(struct be_req *breq) goto done; }
- if (pd->priv == 1 && pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM && - pd->authtok_size == 0) { + if ((pd->priv == 1) && (pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) && + (sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD)) { DEBUG(4, ("Password reset by root is not supported.\n")); pd->pam_status = PAM_PERM_DENIED; dp_err = DP_ERR_OK; @@ -782,25 +779,9 @@ void sdap_pam_chpass_handler(struct be_req *breq) state->pd = pd; state->username = pd->user; state->ctx = ctx; - state->password = talloc_strndup(state, - (char *)pd->authtok, pd->authtok_size); - if (!state->password) goto done; - talloc_set_destructor((TALLOC_CTX *)state->password, - password_destructor);
- if (pd->cmd == SSS_PAM_CHAUTHTOK) { - state->new_password = talloc_strndup(state, - (char *)pd->newauthtok, - pd->newauthtok_size); - if (!state->new_password) goto done; - talloc_set_destructor((TALLOC_CTX *)state->new_password, - password_destructor); - } - - authtok.data = (uint8_t *)state->password; - authtok.length = strlen(state->password); - subreq = auth_send(breq, breq->be_ctx->ev, - ctx, state->username, authtok, true); + subreq = auth_send(breq, breq->be_ctx->ev, ctx, + state->username, &pd->authtok, true); if (!subreq) goto done;
tevent_req_set_callback(subreq, sdap_auth4chpass_done, state); @@ -887,18 +868,30 @@ static void sdap_auth4chpass_done(struct tevent_req *req) state->pd->pam_status = PAM_MODULE_UNKNOWN; goto done; } else { + const char *password; + const char *new_password; + + ret = sss_authtok_get_password(&state->pd->authtok, + &password, NULL); + if (ret) { + state->pd->pam_status = PAM_SYSTEM_ERR; + goto done; + } + ret = sss_authtok_get_password(&state->pd->newauthtok, + &new_password, NULL); + if (ret) { + state->pd->pam_status = PAM_SYSTEM_ERR; + goto done; + } + subreq = sdap_exop_modify_passwd_send(state, state->breq->be_ctx->ev, - state->sh, - state->dn, - state->password, - state->new_password); - + state->sh, state->dn, + password, new_password); if (!subreq) { DEBUG(2, ("Failed to change password for %s\n", state->username)); goto done; } - tevent_req_set_callback(subreq, sdap_pam_chpass_done, state); return; } @@ -1013,8 +1006,6 @@ done: struct sdap_pam_auth_state { struct be_req *breq; struct pam_data *pd; - const char *username; - struct dp_opt_blob password; };
static void sdap_pam_auth_done(struct tevent_req *req); @@ -1049,12 +1040,9 @@ void sdap_pam_auth_handler(struct be_req *breq)
state->breq = breq; state->pd = pd; - state->username = pd->user; - state->password.data = pd->authtok; - state->password.length = pd->authtok_size;
subreq = auth_send(breq, breq->be_ctx->ev, ctx, - state->username, state->password, + pd->user, &pd->authtok, pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM ? true : false); if (!subreq) goto done;
@@ -1088,6 +1076,7 @@ static void sdap_pam_auth_done(struct tevent_req *req) enum pwexpire pw_expire_type; struct be_ctx *be_ctx = state->breq->be_ctx; void *pw_expire_data; + const char *password; int dp_err = DP_ERR_OK; int ret;
@@ -1170,26 +1159,19 @@ static void sdap_pam_auth_done(struct tevent_req *req) if (result == SDAP_AUTH_SUCCESS && state->breq->be_ctx->domain->cache_credentials) {
- char *password = talloc_strndup(state, (char *) - state->password.data, - state->password.length); - /* password caching failures are not fatal errors */ - if (!password) { - DEBUG(2, ("Failed to cache password for %s\n", state->username)); - goto done; + ret = sss_authtok_get_password(&state->pd->authtok, &password, NULL); + if (ret == EOK) { + ret = sysdb_cache_password(state->breq->be_ctx->sysdb, + state->pd->user, password); } - talloc_set_destructor((TALLOC_CTX *)password, password_destructor); - - ret = sysdb_cache_password(state->breq->be_ctx->sysdb, - state->username, password);
/* password caching failures are not fatal errors */ if (ret != EOK) { DEBUG(2, ("Failed to cache password for %s\n", - state->username)); + state->pd->user)); } else { DEBUG(4, ("Password successfully cached for %s\n", - state->username)); + state->pd->user)); } goto done; } diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c index e0440625d279fbbaa1cc2e6343b73f5a247371f7..84497b75ef586b58e27cc4dc9e6b8b3244464676 100644 --- a/src/providers/ldap/sdap_async.c +++ b/src/providers/ldap/sdap_async.c @@ -502,8 +502,8 @@ struct tevent_req *sdap_exop_modify_passwd_send(TALLOC_CTX *memctx, struct tevent_context *ev, struct sdap_handle *sh, char *user_dn, - char *password, - char *new_password) + const char *password, + const char *new_password) { struct tevent_req *req = NULL; struct sdap_exop_modify_passwd_state *state; diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h index 8c16d94e6486336e92b6112cd8b5a2dff4c97957..c5dc17037cd6d2c4ae88aa60d43d517eb2958085 100644 --- a/src/providers/ldap/sdap_async.h +++ b/src/providers/ldap/sdap_async.h @@ -108,8 +108,7 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, const char *sasl_mech, const char *sasl_user, const char *user_dn, - const char *authtok_type, - struct dp_opt_blob authtok); + struct sss_auth_token *authtok);
int sdap_auth_recv(struct tevent_req *req, TALLOC_CTX *memctx, @@ -128,8 +127,8 @@ struct tevent_req *sdap_exop_modify_passwd_send(TALLOC_CTX *memctx, struct tevent_context *ev, struct sdap_handle *sh, char *user_dn, - char *password, - char *new_password); + const char *password, + const char *new_password); int sdap_exop_modify_passwd_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, enum sdap_result *result, char **user_error_msg); diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c index ff99248433026608f06fc548824fa2dd25aaacaa..da50f4ad49ab4319b309cf6861f801014ac47102 100644 --- a/src/providers/ldap/sdap_async_connection.c +++ b/src/providers/ldap/sdap_async_connection.c @@ -493,7 +493,7 @@ static struct tevent_req *simple_bind_send(TALLOC_CTX *memctx, DEBUG(4, ("Executing simple bind as: %s\n", state->user_dn));
ret = ldap_sasl_bind(state->sh->ldap, state->user_dn, LDAP_SASL_SIMPLE, - state->pw, request_controls, NULL, &msgid); + pw, request_controls, NULL, &msgid); if (ctrls[0]) ldap_control_free(ctrls[0]); if (ret == -1 || msgid == -1) { ret = ldap_get_option(state->sh->ldap, @@ -1082,18 +1082,12 @@ int sdap_kinit_recv(struct tevent_req *req, /* ==Authenticaticate-User-by-DN========================================== */
struct sdap_auth_state { - const char *user_dn; - struct berval pw; struct sdap_ppolicy_data *ppolicy; - - int result; bool is_sasl; + int result; };
static void sdap_auth_done(struct tevent_req *subreq); -static int sdap_auth_get_authtok(const char *authtok_type, - struct dp_opt_blob authtok, - struct berval *pw);
/* TODO: handle sasl_cred */ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, @@ -1102,31 +1096,14 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, const char *sasl_mech, const char *sasl_user, const char *user_dn, - const char *authtok_type, - struct dp_opt_blob authtok) + struct sss_auth_token *authtok) { struct tevent_req *req, *subreq; struct sdap_auth_state *state; - int ret;
req = tevent_req_create(memctx, &state, struct sdap_auth_state); if (!req) return NULL;
- state->user_dn = user_dn; - - ret = sdap_auth_get_authtok(authtok_type, authtok, &state->pw); - if (ret != EOK) { - if (ret == ENOSYS) { - DEBUG(1, ("Getting authtok is not supported with the " - "crypto library compiled with, authentication " - "might fail!\n")); - } else { - DEBUG(1, ("Cannot parse authtok.\n")); - tevent_req_error(req, ret); - return tevent_req_post(req, ev); - } - } - if (sasl_mech) { state->is_sasl = true; subreq = sasl_bind_send(state, ev, sh, sasl_mech, sasl_user, NULL); @@ -1135,8 +1112,27 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, return tevent_req_post(req, ev); } } else { + const char *password = NULL; + struct berval pw; + size_t pwlen; + errno_t ret; + + ret = sss_authtok_get_password(authtok, &password, &pwlen); + if (ret != EOK) { + DEBUG(1, ("Cannot parse authtok.\n")); + tevent_req_error(req, ret); + return tevent_req_post(req, ev); + } + /* Treat a zero-length password as a failure */ + if (*password == '\0') { + tevent_req_error(req, ENOENT); + return tevent_req_post(req, ev); + } + pw.bv_val = discard_const(password); + pw.bv_len = pwlen - 1; + state->is_sasl = false; - subreq = simple_bind_send(state, ev, sh, user_dn, &state->pw); + subreq = simple_bind_send(state, ev, sh, user_dn, &pw); if (!subreq) { tevent_req_error(req, ENOMEM); return tevent_req_post(req, ev); @@ -1598,6 +1594,10 @@ static void sdap_cli_auth_step(struct tevent_req *req) SDAP_SASL_MECH); const char *user_dn = dp_opt_get_string(state->opts->basic, SDAP_DEFAULT_BIND_DN); + const char *authtok_type; + struct dp_opt_blob authtok_blob; + struct sss_auth_token authtok = { 0 }; + errno_t ret;
/* Set the LDAP expiration time * If SASL has already set it, use the sooner of the two @@ -1620,17 +1620,31 @@ static void sdap_cli_auth_step(struct tevent_req *req) return; }
- subreq = sdap_auth_send(state, - state->ev, - state->sh, - sasl_mech, + authtok_type = dp_opt_get_string(state->opts->basic, + SDAP_DEFAULT_AUTHTOK_TYPE); + if (authtok_type != NULL) { + if (strcasecmp(authtok_type, "password") != 0) { + DEBUG(SSSDBG_TRACE_LIBS, ("Invalid authtoken type\n")); + tevent_req_error(req, EINVAL); + return; + } + authtok_blob = dp_opt_get_blob(state->opts->basic, + SDAP_DEFAULT_AUTHTOK); + + ret = sss_authtok_set_password(state, &authtok, + (const char *)authtok_blob.data, + authtok_blob.length); + if (ret) { + tevent_req_error(req, ret); + return; + } + } + + subreq = sdap_auth_send(state, state->ev, + state->sh, sasl_mech, dp_opt_get_string(state->opts->basic, - SDAP_SASL_AUTHID), - user_dn, - dp_opt_get_string(state->opts->basic, - SDAP_DEFAULT_AUTHTOK_TYPE), - dp_opt_get_blob(state->opts->basic, - SDAP_DEFAULT_AUTHTOK)); + SDAP_SASL_AUTHID), + user_dn, &authtok); if (!subreq) { tevent_req_error(req, ENOMEM); return; diff --git a/src/providers/proxy/proxy.h b/src/providers/proxy/proxy.h index cea03382517231cdf2b96069ab93dfb7967b46a6..962cb28fc7d6362c45d268f289ffbce103a6e738 100644 --- a/src/providers/proxy/proxy.h +++ b/src/providers/proxy/proxy.h @@ -89,11 +89,8 @@ struct proxy_nss_ops { };
struct authtok_conv { - uint32_t authtok_size; - uint8_t *authtok; - - uint32_t newauthtok_size; - uint8_t *newauthtok; + struct sss_auth_token authtok; + struct sss_auth_token newauthtok;
bool sent_old; }; diff --git a/src/providers/proxy/proxy_auth.c b/src/providers/proxy/proxy_auth.c index 8088283fa8147f75b7d8eb4c83c63208163c9375..3430f38b282eff2da24735f8d635a952edde8888 100644 --- a/src/providers/proxy/proxy_auth.c +++ b/src/providers/proxy/proxy_auth.c @@ -712,7 +712,7 @@ static void proxy_child_done(struct tevent_req *req) struct proxy_client_ctx *client_ctx = tevent_req_callback_data(req, struct proxy_client_ctx); struct pam_data *pd = NULL; - char *password; + const char *password; int ret; struct tevent_immediate *imm;
@@ -747,17 +747,15 @@ static void proxy_child_done(struct tevent_req *req)
/* Check if we need to save the cached credentials */ if ((pd->cmd == SSS_PAM_AUTHENTICATE || pd->cmd == SSS_PAM_CHAUTHTOK) && - pd->pam_status == PAM_SUCCESS && - client_ctx->be_req->be_ctx->domain->cache_credentials) { - password = talloc_strndup(client_ctx->be_req, - (char *) pd->authtok, - pd->authtok_size); - if (!password) { + (pd->pam_status == PAM_SUCCESS) && + client_ctx->be_req->be_ctx->domain->cache_credentials) { + + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + if (ret) { /* password caching failures are not fatal errors */ DEBUG(2, ("Failed to cache password\n")); goto done; } - talloc_set_destructor((TALLOC_CTX *)password, password_destructor);
ret = sysdb_cache_password(client_ctx->be_req->be_ctx->sysdb, pd->user, password); diff --git a/src/providers/proxy/proxy_child.c b/src/providers/proxy/proxy_child.c index c575948a7036d9b73d93bd00e111834b12d28e7d..556dbf9b5488d75f0fa60386958f61b95d61fba2 100644 --- a/src/providers/proxy/proxy_child.c +++ b/src/providers/proxy/proxy_child.c @@ -80,6 +80,9 @@ static int proxy_internal_conv(int num_msg, const struct pam_message **msgm, int i; struct pam_response *reply; struct authtok_conv *auth_data; + const char *password; + size_t pwlen; + errno_t ret;
auth_data = talloc_get_type(appdata_ptr, struct authtok_conv);
@@ -94,11 +97,13 @@ static int proxy_internal_conv(int num_msg, const struct pam_message **msgm, case PAM_PROMPT_ECHO_OFF: DEBUG(4, ("Conversation message: [%s]\n", msgm[i]->msg)); reply[i].resp_retcode = 0; - reply[i].resp = calloc(auth_data->authtok_size + 1, - sizeof(char)); + + ret = sss_authtok_get_password(&auth_data->authtok, + &password, &pwlen); + if (ret) goto failed; + reply[i].resp = calloc(pwlen + 1, sizeof(char)); if (reply[i].resp == NULL) goto failed; - memcpy(reply[i].resp, auth_data->authtok, - auth_data->authtok_size); + memcpy(reply[i].resp, password, pwlen + 1);
break; default: @@ -124,6 +129,9 @@ static int proxy_chauthtok_conv(int num_msg, const struct pam_message **msgm, int i; struct pam_response *reply; struct authtok_conv *auth_data; + const char *password; + size_t pwlen; + errno_t ret;
auth_data = talloc_get_type(appdata_ptr, struct authtok_conv);
@@ -141,20 +149,23 @@ static int proxy_chauthtok_conv(int num_msg, const struct pam_message **msgm, reply[i].resp_retcode = 0; if (!auth_data->sent_old) { /* The first prompt will be asking for the old authtok */ - reply[i].resp = calloc(auth_data->authtok_size + 1, - sizeof(char)); + ret = sss_authtok_get_password(&auth_data->authtok, + &password, &pwlen); + if (ret) goto failed; + reply[i].resp = calloc(pwlen + 1, sizeof(char)); if (reply[i].resp == NULL) goto failed; - memcpy(reply[i].resp, auth_data->authtok, - auth_data->authtok_size); + memcpy(reply[i].resp, password, pwlen + 1); auth_data->sent_old = true; } else { /* Subsequent prompts are looking for the new authtok */ - reply[i].resp = calloc(auth_data->newauthtok_size + 1, - sizeof(char)); + ret = sss_authtok_get_password(&auth_data->newauthtok, + &password, &pwlen); + if (ret) goto failed; + reply[i].resp = calloc(pwlen + 1, sizeof(char)); if (reply[i].resp == NULL) goto failed; - memcpy(reply[i].resp, auth_data->newauthtok, - auth_data->newauthtok_size); + memcpy(reply[i].resp, password, pwlen + 1); + auth_data->sent_old = true; }
break; @@ -213,8 +224,8 @@ static errno_t call_pam_stack(const char *pam_target, struct pam_data *pd) } switch (pd->cmd) { case SSS_PAM_AUTHENTICATE: - auth_data->authtok_size = pd->authtok_size; - auth_data->authtok = pd->authtok; + sss_authtok_copy(auth_data, &pd->authtok, + &auth_data->authtok); pam_status = pam_authenticate(pamh, 0); break; case SSS_PAM_SETCRED: @@ -230,21 +241,21 @@ static errno_t call_pam_stack(const char *pam_target, struct pam_data *pd) pam_status=pam_close_session(pamh, 0); break; case SSS_PAM_CHAUTHTOK: - auth_data->authtok_size = pd->authtok_size; - auth_data->authtok = pd->authtok; + sss_authtok_copy(auth_data, &pd->authtok, + &auth_data->authtok); if (pd->priv != 1) { pam_status = pam_authenticate(pamh, 0); auth_data->sent_old = false; if (pam_status != PAM_SUCCESS) break; } - auth_data->newauthtok_size = pd->newauthtok_size; - auth_data->newauthtok = pd->newauthtok; + sss_authtok_copy(auth_data, &pd->newauthtok, + &auth_data->newauthtok); pam_status = pam_chauthtok(pamh, 0); break; case SSS_PAM_CHAUTHTOK_PRELIM: if (pd->priv != 1) { - auth_data->authtok_size = pd->authtok_size; - auth_data->authtok = pd->authtok; + sss_authtok_copy(auth_data, &pd->authtok, + &auth_data->authtok); pam_status = pam_authenticate(pamh, 0); } else { pam_status = PAM_SUCCESS; diff --git a/src/responder/pam/pam_LOCAL_domain.c b/src/responder/pam/pam_LOCAL_domain.c index 71446b4f8da53bfe4c0707621fafb228da5f808c..23eb7a2a8ddd3ae4480030633be867564b7f59f2 100644 --- a/src/responder/pam/pam_LOCAL_domain.c +++ b/src/responder/pam/pam_LOCAL_domain.c @@ -154,22 +154,19 @@ static void do_pam_acct_mgmt(struct LOCAL_request *lreq) static void do_pam_chauthtok(struct LOCAL_request *lreq) { int ret; - char *newauthtok; + const char *password; char *salt; char *new_hash; struct pam_data *pd;
pd = lreq->preq->pd;
- newauthtok = talloc_strndup(lreq, (char *) pd->newauthtok, - pd->newauthtok_size); - NULL_CHECK_OR_JUMP(newauthtok, ("talloc_strndup failed.\n"), lreq->error, - ENOMEM, done); - memset(pd->newauthtok, 0, pd->newauthtok_size); - - if (strlen(newauthtok) == 0) { + ret = sss_authtok_get_password(&pd->newauthtok, &password, NULL); + if (ret) { /* TODO: should we allow null passwords via a config option ? */ - DEBUG(1, ("Empty passwords are not allowed!\n")); + if (ret == ENOENT) { + DEBUG(1, ("Empty passwords are not allowed!\n")); + } lreq->error = EINVAL; goto done; } @@ -179,11 +176,10 @@ static void do_pam_chauthtok(struct LOCAL_request *lreq) lreq->error, ret, done); DEBUG(4, ("Using salt [%s]\n", salt));
- ret = s3crypt_sha512(lreq, newauthtok, salt, &new_hash); + ret = s3crypt_sha512(lreq, password, salt, &new_hash); NEQ_CHECK_OR_JUMP(ret, EOK, ("Hash generation failed.\n"), lreq->error, ret, done); DEBUG(4, ("New hash [%s]\n", new_hash)); - memset(newauthtok, 0, pd->newauthtok_size);
lreq->mod_attrs = sysdb_new_attrs(lreq); NULL_CHECK_OR_JUMP(lreq->mod_attrs, ("sysdb_new_attrs failed.\n"), @@ -204,7 +200,7 @@ static void do_pam_chauthtok(struct LOCAL_request *lreq) lreq->error, ret, done);
done: - return; + sss_authtok_set_empty(&pd->newauthtok); }
int LOCAL_pam_handler(struct pam_auth_req *preq) @@ -223,9 +219,9 @@ int LOCAL_pam_handler(struct pam_auth_req *preq) NULL}; struct ldb_result *res; const char *username = NULL; - const char *password = NULL; + const char *pwdhash = NULL; char *new_hash = NULL; - char *authtok = NULL; + const char *password; struct pam_data *pd = preq->pd; int ret;
@@ -287,25 +283,22 @@ int LOCAL_pam_handler(struct pam_auth_req *preq) DEBUG(4, ("allowing root to reset a password.\n")); break; } - authtok = talloc_strndup(lreq, (char *) pd->authtok, - pd->authtok_size); - NULL_CHECK_OR_JUMP(authtok, ("talloc_strndup failed.\n"), - lreq->error, ENOMEM, done); - memset(pd->authtok, 0, pd->authtok_size); + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + NEQ_CHECK_OR_JUMP(ret, EOK, ("Failed to get password.\n"), + lreq->error, ret, done);
- password = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_PWD, NULL); - NULL_CHECK_OR_JUMP(password, ("No password stored.\n"), + pwdhash = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_PWD, NULL); + NULL_CHECK_OR_JUMP(pwdhash, ("No password stored.\n"), lreq->error, LDB_ERR_NO_SUCH_ATTRIBUTE, done); - DEBUG(4, ("user: [%s], password hash: [%s]\n", username, password)); + DEBUG(4, ("user: [%s], password hash: [%s]\n", username, pwdhash));
- ret = s3crypt_sha512(lreq, authtok, password, &new_hash); - memset(authtok, 0, pd->authtok_size); + ret = s3crypt_sha512(lreq, password, pwdhash, &new_hash); NEQ_CHECK_OR_JUMP(ret, EOK, ("nss_sha512_crypt failed.\n"), lreq->error, ret, done);
DEBUG(4, ("user: [%s], new hash: [%s]\n", username, new_hash));
- if (strcmp(new_hash, password) != 0) { + if (strcmp(new_hash, pwdhash) != 0) { DEBUG(1, ("Passwords do not match.\n")); do_failed_login(lreq); goto done; @@ -338,13 +331,8 @@ int LOCAL_pam_handler(struct pam_auth_req *preq) }
done: - if (pd->authtok != NULL) - memset(pd->authtok, 0, pd->authtok_size); - if (authtok != NULL) - memset(authtok, 0, pd->authtok_size); - if (pd->newauthtok != NULL) - memset(pd->newauthtok, 0, pd->newauthtok_size); - + sss_authtok_set_empty(&pd->newauthtok); + sss_authtok_set_empty(&pd->authtok); prepare_reply(lreq); return EOK; } diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index ed7438f8d1509568bcd12bbbe7ab73984780bcdd..813894d39767248f74addac8596890ba7213a352 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -49,21 +49,38 @@ enum pam_verbosity {
static void pam_reply(struct pam_auth_req *preq);
-static int extract_authtok(uint32_t *type, uint32_t *size, uint8_t **tok, - size_t data_size, uint8_t *body, size_t blen, - size_t *c) { +static int extract_authtok_v2(TALLOC_CTX *mem_ctx, struct sss_auth_token *tok, + size_t data_size, uint8_t *body, size_t blen, + size_t *c) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + uint8_t *auth_token_data; + int ret = EOK;
if (data_size < sizeof(uint32_t) || *c+data_size > blen || SIZE_T_OVERFLOW(*c, data_size)) return EINVAL; - *size = data_size - sizeof(uint32_t);
- SAFEALIGN_COPY_UINT32_CHECK(type, &body[*c], blen, c); + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, &body[*c], blen, c); + auth_token_length = data_size - sizeof(uint32_t); + auth_token_data = body+(*c);
- *tok = body+(*c); + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_set_password(mem_ctx, tok, + (const char *)auth_token_data, + auth_token_length); + break; + default: + return EINVAL; + }
- *c += (*size); + *c += auth_token_length;
- return EOK; + return ret; }
static int extract_string(char **var, size_t size, uint8_t *body, size_t blen, @@ -185,14 +202,13 @@ static int pam_parse_in_data_v2(struct sss_domain_info *domains, if (ret != EOK) return ret; break; case SSS_PAM_ITEM_AUTHTOK: - ret = extract_authtok(&pd->authtok_type, &pd->authtok_size, - &pd->authtok, size, body, blen, &c); + ret = extract_authtok_v2(pd, &pd->authtok, + size, body, blen, &c); if (ret != EOK) return ret; break; case SSS_PAM_ITEM_NEWAUTHTOK: - ret = extract_authtok(&pd->newauthtok_type, - &pd->newauthtok_size, - &pd->newauthtok, size, body, blen, &c); + ret = extract_authtok_v2(pd, &pd->newauthtok, + size, body, blen, &c); if (ret != EOK) return ret; break; default: @@ -232,14 +248,44 @@ static int pam_parse_in_data_v3(struct sss_domain_info *domains, return EOK; }
+static int extract_authtok_v1(TALLOC_CTX *mem_ctx, struct sss_auth_token *tok, + uint8_t *body, size_t blen, size_t *c) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + uint8_t *auth_token_data; + int ret = EOK; + + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, &body[*c], blen, c); + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_length, &body[*c], blen, c); + auth_token_data = body+(*c); + + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_set_password(mem_ctx, tok, + (const char *)auth_token_data, + auth_token_length); + break; + default: + return EINVAL; + } + + *c += auth_token_length; + + return ret; +} + static int pam_parse_in_data(struct sss_domain_info *domains, const char *default_domain, struct pam_data *pd, uint8_t *body, size_t blen) { - int start; - int end; - int last; + size_t start; + size_t end; + size_t last; int ret;
last = blen - 1; @@ -269,45 +315,15 @@ static int pam_parse_in_data(struct sss_domain_info *domains, if (body[end++] != '\0') return EINVAL; pd->rhost = (char *) &body[start];
- start = end; - pd->authtok_type = (int) body[start]; - - start += sizeof(uint32_t); - pd->authtok_size = (int) body[start]; - if (pd->authtok_size >= blen) return EINVAL; - - start += sizeof(uint32_t); - end = start + pd->authtok_size; - if (pd->authtok_size == 0) { - pd->authtok = NULL; - } else { - if (end <= blen) { - pd->authtok = (uint8_t *) &body[start]; - } else { - DEBUG(1, ("Invalid authtok size: %d\n", pd->authtok_size)); - return EINVAL; - } + ret = extract_authtok_v1(pd, &pd->authtok, body, blen, &end); + if (ret) { + DEBUG(1, ("Invalid auth token\n")); + return ret; } - - start = end; - pd->newauthtok_type = (int) body[start]; - - start += sizeof(uint32_t); - pd->newauthtok_size = (int) body[start]; - if (pd->newauthtok_size >= blen) return EINVAL; - - start += sizeof(uint32_t); - end = start + pd->newauthtok_size; - - if (pd->newauthtok_size == 0) { - pd->newauthtok = NULL; - } else { - if (end <= blen) { - pd->newauthtok = (uint8_t *) &body[start]; - } else { - DEBUG(1, ("Invalid newauthtok size: %d\n", pd->newauthtok_size)); - return EINVAL; - } + ret = extract_authtok_v1(pd, &pd->newauthtok, body, blen, &end); + if (ret) { + DEBUG(1, ("Invalid new auth token\n")); + return ret; }
DEBUG_PAM_DATA(4, pd); @@ -763,9 +779,9 @@ static void pam_reply(struct pam_auth_req *preq) goto done; }
- password = talloc_strndup(preq, pd->authtok, pd->authtok_size); - if (!password) { - DEBUG(0, ("Fatal: Out of memory copying password\n")); + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + if (ret) { + DEBUG(0, ("Failed to get password.\n")); goto done; }
@@ -775,10 +791,6 @@ static void pam_reply(struct pam_auth_req *preq) &exp_date, &delay_until);
pam_handle_cached_login(preq, ret, exp_date, delay_until); - if (password) { - for (i = 0; password[i]; i++) password[i] = 0; - talloc_zfree(password); - } return; } break; diff --git a/src/tests/krb5_child-test.c b/src/tests/krb5_child-test.c index 34d025b77b27a27e6131c1895c6c02644f921e5d..a72a3519985292456db6b9bbf9bccdcf678068a6 100644 --- a/src/tests/krb5_child-test.c +++ b/src/tests/krb5_child-test.c @@ -167,6 +167,9 @@ create_dummy_pam_data(TALLOC_CTX *mem_ctx, const char *user, const char *password) { struct pam_data *pd; + const char *authtok; + size_t authtok_len; + errno_t ret;
pd = talloc_zero(mem_ctx, struct pam_data); if (!pd) goto fail; @@ -175,12 +178,12 @@ create_dummy_pam_data(TALLOC_CTX *mem_ctx, const char *user, pd->user = talloc_strdup(pd, user); if (!pd->user) goto fail;
- pd->authtok = discard_const(talloc_strdup(pd, password)); - if (!pd->authtok) goto fail; - pd->authtok_size = strlen(password); - pd->authtok_type = SSS_AUTHTOK_TYPE_PASSWORD; + ret = sss_authtok_set_password(pd, &pd->authtok, password, 0); + if (ret) goto fail; + + (void)sss_authtok_get_password(&pd->authtok, &authtok, &authtok_len); DEBUG(SSSDBG_FUNC_DATA, ("Authtok [%s] len [%d]\n", - pd->authtok, pd->authtok_size)); + authtok, (int)authtok_len));
return pd;
On 11/24/2012 05:36 AM, Simo Sorce wrote:
Rebased on top of master. Tested and working.
Simo Sorce (4): Code can only check for cached passwords Add function to safely wipe memory. Add authtok utility functions. Change pam data auth tokens.
Makefile.am | 4 + src/db/sysdb.h | 3 +- src/db/sysdb_ops.c | 13 +-- src/providers/data_provider.h | 9 +- src/providers/dp_auth_util.c | 76 +++++--- src/providers/dp_pam_data_util.c | 113 ++++++------ src/providers/ipa/ipa_auth.c | 6 +- src/providers/krb5/krb5_auth.c | 52 +++--- src/providers/krb5/krb5_child.c | 148 ++++++++------- src/providers/krb5/krb5_child_handler.c | 59 +++++- .../krb5/krb5_delayed_online_authentication.c | 50 ++++-- src/providers/krb5/krb5_renew_tgt.c | 18 +-- src/providers/ldap/ldap_auth.c | 90 ++++------ src/providers/ldap/sdap_async.c | 4 +- src/providers/ldap/sdap_async.h | 7 +- src/providers/ldap/sdap_async_connection.c | 88 +++++---- src/providers/proxy/proxy.h | 7 +- src/providers/proxy/proxy_auth.c | 14 +- src/providers/proxy/proxy_child.c | 51 +++-- src/responder/pam/pam_LOCAL_domain.c | 52 ++---- src/responder/pam/pamsrv_cmd.c | 159 +++++++++------- src/tests/krb5_child-test.c | 13 +- src/tests/sysdb-tests.c | 6 +- src/util/authtok.c | 195 ++++++++++++++++++++ src/util/authtok.h | 180 ++++++++++++++++++ src/util/util.c | 9 + src/util/util.h | 9 + 27 files changed, 950 insertions(+), 485 deletions(-) create mode 100644 src/util/authtok.c create mode 100644 src/util/authtok.h
sssd-devel mailing list sssd-devel@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/sssd-devel
Hi, can you rebase one more time please?
Rebased again as requested by Pavel
Simo Sorce (4): Code can only check for cached passwords Add function to safely wipe memory. Add authtok utility functions. Change pam data auth tokens.
Makefile.am | 4 + src/db/sysdb.h | 3 +- src/db/sysdb_ops.c | 13 +-- src/providers/data_provider.h | 9 +- src/providers/dp_auth_util.c | 76 +++++--- src/providers/dp_pam_data_util.c | 113 ++++++------ src/providers/ipa/ipa_auth.c | 6 +- src/providers/krb5/krb5_auth.c | 52 +++--- src/providers/krb5/krb5_child.c | 148 ++++++++------- src/providers/krb5/krb5_child_handler.c | 59 +++++- .../krb5/krb5_delayed_online_authentication.c | 50 ++++-- src/providers/krb5/krb5_renew_tgt.c | 18 +-- src/providers/ldap/ldap_auth.c | 90 ++++------ src/providers/ldap/sdap_async.c | 4 +- src/providers/ldap/sdap_async.h | 7 +- src/providers/ldap/sdap_async_connection.c | 88 +++++---- src/providers/proxy/proxy.h | 7 +- src/providers/proxy/proxy_auth.c | 14 +- src/providers/proxy/proxy_child.c | 51 +++-- src/responder/pam/pam_LOCAL_domain.c | 52 ++---- src/responder/pam/pamsrv_cmd.c | 159 +++++++++------- src/tests/krb5_child-test.c | 13 +- src/tests/sysdb-tests.c | 6 +- src/util/authtok.c | 195 ++++++++++++++++++++ src/util/authtok.h | 180 ++++++++++++++++++ src/util/util.c | 9 + src/util/util.h | 9 + 27 files changed, 950 insertions(+), 485 deletions(-) create mode 100644 src/util/authtok.c create mode 100644 src/util/authtok.h
Make it clear to the API users that we can not take arbitrary auth tokens. We can only take a password for now so simplify and clarify the interface. --- src/db/sysdb.h | 3 +-- src/db/sysdb_ops.c | 12 +----------- src/providers/krb5/krb5_auth.c | 21 +++++++++++++++++---- src/responder/pam/pamsrv_cmd.c | 39 ++++++++++++++++++++++++--------------- src/tests/sysdb-tests.c | 6 ++---- 5 files changed, 45 insertions(+), 36 deletions(-)
diff --git a/src/db/sysdb.h b/src/db/sysdb.h index ed00c165952aa80102b88c9e857355f2ef27d570..892414797304a1ba86a041279aea9bcafe1fd3cd 100644 --- a/src/db/sysdb.h +++ b/src/db/sysdb.h @@ -778,8 +778,7 @@ errno_t check_failed_login_attempts(struct confdb_ctx *cdb, time_t *delayed_until); int sysdb_cache_auth(struct sysdb_ctx *sysdb, const char *name, - const uint8_t *authtok, - size_t authtok_size, + const char *password, struct confdb_ctx *cdb, bool just_check, time_t *_expire_date, diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c index 80a323b12901b40f6df0c4cd0f0b23b4cf2cf2b2..e213023e3f1f1342984b7b2464a23a4544df9010 100644 --- a/src/db/sysdb_ops.c +++ b/src/db/sysdb_ops.c @@ -2674,8 +2674,7 @@ done:
int sysdb_cache_auth(struct sysdb_ctx *sysdb, const char *name, - const uint8_t *authtok, - size_t authtok_size, + const char *password, struct confdb_ctx *cdb, bool just_check, time_t *_expire_date, @@ -2690,7 +2689,6 @@ int sysdb_cache_auth(struct sysdb_ctx *sysdb, struct ldb_message *ldb_msg; const char *userhash; char *comphash; - char *password = NULL; uint64_t lastLogin = 0; int cred_expiration; uint32_t failed_login_attempts = 0; @@ -2776,13 +2774,6 @@ int sysdb_cache_auth(struct sysdb_ctx *sysdb,
/* TODO: verify user account (disabled, expired ...) */
- password = talloc_strndup(tmp_ctx, (const char *)authtok, authtok_size); - if (password == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - ret = ENOMEM; - goto done; - } - userhash = ldb_msg_find_attr_as_string(ldb_msg, SYSDB_CACHEDPWD, NULL); if (userhash == NULL || *userhash == '\0') { DEBUG(4, ("Cached credentials not available.\n")); @@ -2866,7 +2857,6 @@ done: if (_delayed_until != NULL) { *_delayed_until = delayed_until; } - if (password) for (i = 0; password[i]; i++) password[i] = 0; if (ret) { ldb_transaction_cancel(sysdb->ldb); } else { diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c index 7104b3127e04891fed7370a6241c60865372632b..5ef6cfc28625c55d850b73dc8cc621f33da1bdce 100644 --- a/src/providers/krb5/krb5_auth.c +++ b/src/providers/krb5/krb5_auth.c @@ -278,16 +278,23 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, struct pam_data *pd, uid_t uid, int *pam_status, int *dp_err) { + char *password = NULL; errno_t ret;
- ret = sysdb_cache_auth(sysdb, pd->user, pd->authtok, - pd->authtok_size, cdb, true, NULL, - NULL); + password = talloc_strndup(state, pd->authtok, pd->authtok_size); + if (!password) { + DEBUG(0, ("Out of memory copying password\n")); + *pam_status = PAM_SYSTEM_ERR; + *dp_err = DP_ERR_OK; + return; + } + + ret = sysdb_cache_auth(sysdb, pd->user, password, cdb, true, NULL, NULL); if (ret != EOK) { DEBUG(1, ("Offline authentication failed\n")); *pam_status = cached_login_pam_status(ret); *dp_err = DP_ERR_OK; - return; + goto done; }
ret = add_user_to_delayed_online_authentication(krb5_ctx, pd, uid); @@ -297,6 +304,12 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, } *pam_status = PAM_AUTHINFO_UNAVAIL; *dp_err = DP_ERR_OFFLINE; + +done: + if (password) { + for (i = 0; password[i]; i++) password[i] = 0; + talloc_zfree(password); + } }
static errno_t krb5_auth_prepare_ccache_file(struct krb5child_req *kr, diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index 4269642206cc0295c0046de4e59a3ad8f1044d1a..ed7438f8d1509568bcd12bbbe7ab73984780bcdd 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -733,7 +733,6 @@ static void pam_reply(struct pam_auth_req *preq) struct timeval tv; struct tevent_timer *te; struct pam_data *pd; - struct sysdb_ctx *sysdb; struct pam_ctx *pctx; uint32_t user_info_type; time_t exp_date = -1; @@ -753,24 +752,34 @@ static void pam_reply(struct pam_auth_req *preq) if ((preq->domain != NULL) && (preq->domain->cache_credentials == true) && (pd->offline_auth == false)) { + const char *password = NULL;
- /* do auth with offline credentials */ - pd->offline_auth = true; + /* do auth with offline credentials */ + pd->offline_auth = true;
- sysdb = preq->domain->sysdb; - if (sysdb == NULL) { - DEBUG(0, ("Fatal: Sysdb CTX not found for " - "domain [%s]!\n", preq->domain->name)); - goto done; - } + if (preq->domain->sysdb == NULL) { + DEBUG(0, ("Fatal: Sysdb CTX not found for domain" + " [%s]!\n", preq->domain->name)); + goto done; + }
- ret = sysdb_cache_auth(sysdb, pd->user, - pd->authtok, pd->authtok_size, - pctx->rctx->cdb, false, - &exp_date, &delay_until); + password = talloc_strndup(preq, pd->authtok, pd->authtok_size); + if (!password) { + DEBUG(0, ("Fatal: Out of memory copying password\n")); + goto done; + }
- pam_handle_cached_login(preq, ret, exp_date, delay_until); - return; + ret = sysdb_cache_auth(preq->domain->sysdb, + pd->user, password, + pctx->rctx->cdb, false, + &exp_date, &delay_until); + + pam_handle_cached_login(preq, ret, exp_date, delay_until); + if (password) { + for (i = 0; password[i]; i++) password[i] = 0; + talloc_zfree(password); + } + return; } break; case SSS_PAM_CHAUTHTOK_PRELIM: diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c index 74b75233d7a5cf027ffdf581cbc9942ba2cc2b95..06cda816d79986d099d24457c40af7264b5a1a44 100644 --- a/src/tests/sysdb-tests.c +++ b/src/tests/sysdb-tests.c @@ -1576,8 +1576,7 @@ static void cached_authentication_without_expiration(const char *username, return; }
- ret = sysdb_cache_auth(test_ctx->sysdb, data->username, - (const uint8_t *)password, strlen(password), + ret = sysdb_cache_auth(test_ctx->sysdb, data->username, password, test_ctx->confdb, false, &expire_date, &delayed_until);
fail_unless(ret == expected_result, "sysdb_cache_auth request does not " @@ -1636,8 +1635,7 @@ static void cached_authentication_with_expiration(const char *username, data->attrs, SYSDB_MOD_REP); fail_unless(ret == EOK, "Could not modify user %s", data->username);
- ret = sysdb_cache_auth(test_ctx->sysdb, data->username, - (const uint8_t *) password, strlen(password), + ret = sysdb_cache_auth(test_ctx->sysdb, data->username, password, test_ctx->confdb, false, &expire_date, &delayed_until);
fail_unless(ret == expected_result,
This is useful for wiping passwords, as it prevents the compiler from optimizing out a memset to zero before a free() --- src/util/util.c | 9 +++++++++ src/util/util.h | 9 +++++++++ 2 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/src/util/util.c b/src/util/util.c index ab980775a1e4c87b16d32220bccda6cb644e0756..f268fbcd564cd93a2e63097c595cf19b65eb6800 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -700,3 +700,12 @@ bool string_in_list(const char *string, char **list, bool case_sensitive)
return false; } + +void safezero(void *data, size_t size) +{ + volatile uint8_t *p = data; + + while (size--) { + *p++ = 0; + } +} diff --git a/src/util/util.h b/src/util/util.h index c15ca668392105447d073c40666953a0145d375a..1c5f3fc52292e251bf7b8ad4d5b03a9d8a0a3243 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -540,6 +540,15 @@ errno_t add_string_to_list(TALLOC_CTX *mem_ctx, const char *string,
bool string_in_list(const char *string, char **list, bool case_sensitive);
+/** + * @brief Safely zero a segment of memory, + * prevents the compiler from optimizing out + * + * @param data The address of buffer to wipe + * @param s Size of the buffer + */ +void safezero(void *data, size_t size); + /* from sss_tc_utf8.c */ char * sss_tc_utf8_str_tolower(TALLOC_CTX *mem_ctx, const char *s);
These functions allow handling of auth tokens in a completely opaque way, with clear semantics and accessor fucntions that guarantee consistency, proper access to data and error conditions. --- Makefile.am | 2 + src/util/authtok.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/util/authtok.h | 180 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 377 insertions(+), 0 deletions(-) create mode 100644 src/util/authtok.c create mode 100644 src/util/authtok.h
diff --git a/Makefile.am b/Makefile.am index ce3f94f635f918438bf856c523e47c0f09fc328a..1e4442c4a4bdfafccf1db923d650da4d161ae480 100644 --- a/Makefile.am +++ b/Makefile.am @@ -369,6 +369,7 @@ dist_noinst_HEADERS = \ src/util/mmap_cache.h \ src/util/atomic_io.h \ src/util/auth_utils.h \ + src/util/authtok.h \ src/monitor/monitor.h \ src/monitor/monitor_interfaces.h \ src/responder/common/responder.h \ @@ -507,6 +508,7 @@ libsss_util_la_SOURCES = \ src/util/sss_tc_utf8.c \ src/util/murmurhash3.c \ src/util/atomic_io.c \ + src/util/authtok.c \ src/util/sss_selinux.c \ src/util/domain_info_utils.c \ src/util/util_lock.c diff --git a/src/util/authtok.c b/src/util/authtok.c new file mode 100644 index 0000000000000000000000000000000000000000..1f45953378021e9d30559030326134794965b240 --- /dev/null +++ b/src/util/authtok.c @@ -0,0 +1,195 @@ +/* + SSSD - auth utils + + Copyright (C) Simo Sorce simo@redhat.com 2012 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses/. +*/ + +#include "authtok.h" + +enum sss_authtok_type sss_authtok_get_type(struct sss_auth_token *tok) +{ + return tok->type; +} + +size_t sss_authtok_get_size(struct sss_auth_token *tok) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_PASSWORD: + case SSS_AUTHTOK_TYPE_CCFILE: + return tok->length; + default: + return 0; + } +} + +uint8_t *sss_authtok_get_data(struct sss_auth_token *tok) +{ + return (void *)tok->data; +} + +errno_t sss_authtok_get_password(struct sss_auth_token *tok, + const char **pwd, size_t *len) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_EMPTY: + return ENOENT; + case SSS_AUTHTOK_TYPE_PASSWORD: + *pwd = (const char *)tok->data; + if (len) { + *len = tok->length - 1; + } + return EOK; + default: + return EACCES; + } +} + +errno_t sss_authtok_get_ccfile(struct sss_auth_token *tok, + const char **ccfile, size_t *len) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_EMPTY: + return ENOENT; + case SSS_AUTHTOK_TYPE_CCFILE: + *ccfile = (const char *)tok->data; + if (len) { + *len = tok->length - 1; + } + return EOK; + default: + return EACCES; + } +} + +static errno_t sss_authtok_set_string(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + enum sss_authtok_type type, + const char *context_name, + const char *str, size_t len) +{ + size_t size; + + if (len == 0) { + len = strlen(str); + } else { + while (len > 0 && str[len - 1] == '\0') len--; + } + + if (len == 0) { + /* we do not allow zero length ttyped tokens */ + return EINVAL; + } + + size = len + 1; + + tok->data = talloc_named(mem_ctx, size, context_name); + if (!tok->data) { + return ENOMEM; + } + memcpy(tok->data, str, len); + tok->data[len] = '\0'; + tok->type = type; + tok->length = size; + + return EOK; + +} + +void sss_authtok_set_empty(struct sss_auth_token *tok) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_EMPTY: + return; + case SSS_AUTHTOK_TYPE_PASSWORD: + safezero(tok->data, tok->length); + default: + break; + } + + tok->type = SSS_AUTHTOK_TYPE_EMPTY; + talloc_zfree(tok->data); + tok->length = 0; +} + +errno_t sss_authtok_set_password(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *password, size_t len) +{ + sss_authtok_set_empty(tok); + + return sss_authtok_set_string(mem_ctx, tok, + SSS_AUTHTOK_TYPE_PASSWORD, + "password", password, len); +} + +errno_t sss_authtok_set_ccfile(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *ccfile, size_t len) +{ + sss_authtok_set_empty(tok); + + return sss_authtok_set_string(mem_ctx, tok, + SSS_AUTHTOK_TYPE_CCFILE, + "ccfile", ccfile, len); +} + +errno_t sss_authtok_set(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + enum sss_authtok_type type, + uint8_t *data, size_t len) +{ + switch (type) { + case SSS_AUTHTOK_TYPE_PASSWORD: + return sss_authtok_set_password(mem_ctx, tok, (const char *)data, len); + case SSS_AUTHTOK_TYPE_CCFILE: + return sss_authtok_set_ccfile(mem_ctx, tok, (const char *)data, len); + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + return EOK; + default: + return EINVAL; + } +} + +errno_t sss_authtok_copy(TALLOC_CTX *mem_ctx, + struct sss_auth_token *src, + struct sss_auth_token *dst) +{ + sss_authtok_set_empty(dst); + + if (src->type == SSS_AUTHTOK_TYPE_EMPTY) { + return EOK; + } + + dst->data = talloc_memdup(mem_ctx, src->data, src->length); + if (!dst->data) { + return ENOMEM; + } + dst->length = src->length; + dst->type = src->type; + + return EOK; +} + +void sss_authtok_wipe_password(struct sss_auth_token *tok) +{ + if (tok->type != SSS_AUTHTOK_TYPE_PASSWORD) { + return; + } + + safezero(tok->data, tok->length); +} + diff --git a/src/util/authtok.h b/src/util/authtok.h new file mode 100644 index 0000000000000000000000000000000000000000..c750711ea373506118aab75807dc706c217f6842 --- /dev/null +++ b/src/util/authtok.h @@ -0,0 +1,180 @@ +/* + SSSD - auth utils + + Copyright (C) Simo Sorce simo@redhat.com 2012 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses/. +*/ + +#ifndef __AUTHTOK_H__ +#define __AUTHTOK_H__ + +#include "util/util.h" +#include "sss_client/sss_cli.h" + +/* Auth token structure, + * please never use directly. + * Use ss_authtok_* accesor functions instead + */ +struct sss_auth_token { + enum sss_authtok_type type; + uint8_t *data; + size_t length; +}; + +/** + * @brief Returns the token type + * + * @param tok A pointer to an sss_auth_token + * + * @return A sss_authtok_type (empty, password, ...) + */ +enum sss_authtok_type sss_authtok_get_type(struct sss_auth_token *tok); + +/** + * @brief Returns the token size + * + * @param tok A pointer to an sss_auth_token + * + * @return The current size of the token payload + */ +size_t sss_authtok_get_size(struct sss_auth_token *tok); + +/** + * @brief Get the data buffer + * + * @param tok A pointer to an sss_auth_token + * + * @return A pointer to the token payload + */ +uint8_t *sss_authtok_get_data(struct sss_auth_token *tok); + +/** + * @brief Returns a const string if the auth token is of type + SSS_AUTHTOK_TYPE_PASSWORD, otherwise it returns an error + * + * @param tok A pointer to an sss_auth_token + * @param pwd A pointer to a const char *, that will point to a null + * terminated string + * @param len The length of the password string + * + * @return EOK on success + * ENOENT if the token is empty + * EACCESS if the token is not a password token + */ +errno_t sss_authtok_get_password(struct sss_auth_token *tok, + const char **pwd, size_t *len); + +/** + * @brief Set a password into a an auth token, replacing any previous data + * + * @param mem_ctx A memory context use to allocate the internal data + * @param tok A pointer to a sss_auth_token structure to change + * @param password A string + * @param len The length of the string or, if 0 is passed, + * then strlen(password) will be used internally. + * + * @return EOK on success + * ENOMEM on error + */ +errno_t sss_authtok_set_password(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *password, size_t len); + +/** + * @brief Returns a const string if the auth token is of type + SSS_AUTHTOK_TYPE_CCFILE, otherwise it returns an error + * + * @param tok A pointer to an sss_auth_token + * @param ccfile A pointer to a const char *, that will point to a null + * terminated string + * @param len The length of the string + * + * @return EOK on success + * ENOENT if the token is empty + * EACCESS if the token is not a password token + */ +errno_t sss_authtok_get_ccfile(struct sss_auth_token *tok, + const char **ccfile, size_t *len); + +/** + * @brief Set a cc file name into a an auth token, replacing any previous data + * + * @param mem_ctx A memory context use to allocate the internal data + * @param tok A pointer to a sss_auth_token structure to change + * @param ccfile A null terminated string + * @param len The length of the string + * + * @return EOK on success + * ENOMEM on error + */ +errno_t sss_authtok_set_ccfile(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *ccfile, size_t len); + +/** + * @brief Resets an auth token to the empty status + * + * @param tok A pointer to a sss_auth_token structure to reset + * + * NOTE: This function uses safezero() on the payload if the type + * is SSS_AUTHTOK_TYPE_PASSWORD + */ +void sss_authtok_set_empty(struct sss_auth_token *tok); + +/** + * @brief Set an auth token by type, replacing any previous data + * + * @param mem_ctx A memory context use to allocate the internal data + * @param tok A pointer to a sss_auth_token structure to change + * @param type A valid authtok type + * @param ccfile A data pointer + * @param len The length of the data + * + * @return EOK on success + * ENOMEM or EINVAL on error + */ +errno_t sss_authtok_set(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + enum sss_authtok_type type, + uint8_t *data, size_t len); + +/** + * @brief Copy an auth token from source to destination + * + * @param mem_ctx The memory context to use for allocations on dst + * @param src The source auth token + * @param dst The destination auth token + * + * @return EOK on success + * ENOMEM on error + */ +errno_t sss_authtok_copy(TALLOC_CTX *mem_ctx, + struct sss_auth_token *src, + struct sss_auth_token *dst); + +/** + * @brief Uses safezero to wipe the password from memory if the + * authtoken contains a password, otherwise does nothing. + * + * @param tok A pointer to a sss_auth_token structure to change + * + * NOTE: This function should only be used in destructors or similar + * functions where freing the actual string is unsafe and where it can + * be guaranteed that the auth token will not be used anymore. + * Use sss_authtok_set_empty() in normal circumstances. + */ +void sss_authtok_wipe_password(struct sss_auth_token *tok); + +#endif /* __AUTHTOK_H__ */
Use the new authtok abstraction and interfaces throught the code. --- Makefile.am | 2 + src/db/sysdb_ops.c | 1 - src/providers/data_provider.h | 9 +- src/providers/dp_auth_util.c | 76 +++++++---- src/providers/dp_pam_data_util.c | 113 ++++++++------- src/providers/ipa/ipa_auth.c | 6 +- src/providers/krb5/krb5_auth.c | 55 +++----- src/providers/krb5/krb5_child.c | 148 ++++++++++---------- src/providers/krb5/krb5_child_handler.c | 59 +++++++-- .../krb5/krb5_delayed_online_authentication.c | 50 +++++--- src/providers/krb5/krb5_renew_tgt.c | 18 +-- src/providers/ldap/ldap_auth.c | 90 +++++------- src/providers/ldap/sdap_async.c | 4 +- src/providers/ldap/sdap_async.h | 7 +- src/providers/ldap/sdap_async_connection.c | 88 +++++++----- src/providers/proxy/proxy.h | 7 +- src/providers/proxy/proxy_auth.c | 14 +- src/providers/proxy/proxy_child.c | 51 ++++--- src/responder/pam/pam_LOCAL_domain.c | 52 +++----- src/responder/pam/pamsrv_cmd.c | 134 ++++++++++-------- src/tests/krb5_child-test.c | 13 +- 21 files changed, 529 insertions(+), 468 deletions(-)
diff --git a/Makefile.am b/Makefile.am index 1e4442c4a4bdfafccf1db923d650da4d161ae480..06f6280913e0419210852872663f0220455cc909 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1446,6 +1446,7 @@ krb5_child_SOURCES = \ src/util/user_info_msg.c \ src/util/sss_krb5.c \ src/util/atomic_io.c \ + src/util/authtok.c \ src/util/util.c \ src/util/signal.c \ src/sss_client/common.c @@ -1467,6 +1468,7 @@ ldap_child_SOURCES = \ src/providers/ldap/ldap_child.c \ src/util/sss_krb5.c \ src/util/atomic_io.c \ + src/util/authtok.c \ src/util/util.c \ src/util/signal.c ldap_child_CFLAGS = \ diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c index e213023e3f1f1342984b7b2464a23a4544df9010..c7a5372b99baa534d79e4fb65db7a420d11b5662 100644 --- a/src/db/sysdb_ops.c +++ b/src/db/sysdb_ops.c @@ -2697,7 +2697,6 @@ int sysdb_cache_auth(struct sysdb_ctx *sysdb, time_t expire_date = -1; time_t delayed_until = -1; int ret; - int i;
if (name == NULL || *name == '\0') { DEBUG(1, ("Missing user name.\n")); diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h index bb944509da9f1dc89216266cf62c57fb4127fd57..b370aa51dbe4015a26512a0f003defdb6851bf63 100644 --- a/src/providers/data_provider.h +++ b/src/providers/data_provider.h @@ -41,6 +41,7 @@ #include "sbus/sssd_dbus.h" #include "sbus/sbus_client.h" #include "sss_client/sss_cli.h" +#include "util/authtok.h"
#define DATA_PROVIDER_VERSION 0x0001 #define DATA_PROVIDER_PIPE "private/sbus-dp" @@ -162,18 +163,14 @@ struct response_data {
struct pam_data { int cmd; - uint32_t authtok_type; - uint32_t authtok_size; - uint32_t newauthtok_type; - uint32_t newauthtok_size; char *domain; char *user; char *service; char *tty; char *ruser; char *rhost; - uint8_t *authtok; - uint8_t *newauthtok; + struct sss_auth_token authtok; + struct sss_auth_token newauthtok; uint32_t cli_pid;
int pam_status; diff --git a/src/providers/dp_auth_util.c b/src/providers/dp_auth_util.c index 9a67564b78e558642f4116528d210251a0d9b5fd..54f0ee8ed6f1d537410a91f93e55316fc9b89886 100644 --- a/src/providers/dp_auth_util.c +++ b/src/providers/dp_auth_util.c @@ -24,30 +24,43 @@ bool dp_pack_pam_request(DBusMessage *msg, struct pam_data *pd) { dbus_bool_t db_ret; + const char *service; + const char *tty; + const char *ruser; + const char *rhost; + uint32_t authtok_type; + uint32_t authtok_length; + uint8_t *authtok_data; + uint32_t new_authtok_type; + uint32_t new_authtok_length; + uint8_t *new_authtok_data;
if (pd->user == NULL) return false; - if (pd->service == NULL) pd->service = talloc_strdup(pd, ""); - if (pd->tty == NULL) pd->tty = talloc_strdup(pd, ""); - if (pd->ruser == NULL) pd->ruser = talloc_strdup(pd, ""); - if (pd->rhost == NULL) pd->rhost = talloc_strdup(pd, ""); - + service = pd->service ? pd->service : ""; + tty = pd->tty ? pd->tty : ""; + ruser = pd->ruser ? pd->ruser : ""; + rhost = pd->rhost ? pd->rhost : ""; + authtok_type = (uint32_t)sss_authtok_get_type(&pd->authtok); + authtok_data = sss_authtok_get_data(&pd->authtok); + authtok_length = sss_authtok_get_size(&pd->authtok); + new_authtok_type = (uint32_t)sss_authtok_get_type(&pd->newauthtok); + new_authtok_data = sss_authtok_get_data(&pd->newauthtok); + new_authtok_length = sss_authtok_get_size(&pd->newauthtok);
db_ret = dbus_message_append_args(msg, DBUS_TYPE_INT32, &(pd->cmd), DBUS_TYPE_STRING, &(pd->user), DBUS_TYPE_STRING, &(pd->domain), - DBUS_TYPE_STRING, &(pd->service), - DBUS_TYPE_STRING, &(pd->tty), - DBUS_TYPE_STRING, &(pd->ruser), - DBUS_TYPE_STRING, &(pd->rhost), - DBUS_TYPE_UINT32, &(pd->authtok_type), + DBUS_TYPE_STRING, &service, + DBUS_TYPE_STRING, &tty, + DBUS_TYPE_STRING, &ruser, + DBUS_TYPE_STRING, &rhost, + DBUS_TYPE_UINT32, &authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd->authtok), - (pd->authtok_size), - DBUS_TYPE_UINT32, &(pd->newauthtok_type), + &authtok_data, authtok_length, + DBUS_TYPE_UINT32, &new_authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd->newauthtok), - pd->newauthtok_size, + &new_authtok_data, new_authtok_length, DBUS_TYPE_INT32, &(pd->priv), DBUS_TYPE_UINT32, &(pd->cli_pid), DBUS_TYPE_INVALID); @@ -61,6 +74,12 @@ bool dp_unpack_pam_request(DBusMessage *msg, TALLOC_CTX *mem_ctx, dbus_bool_t db_ret; int ret; struct pam_data pd; + uint32_t authtok_type; + uint32_t authtok_length; + uint8_t *authtok_data; + uint32_t new_authtok_type; + uint32_t new_authtok_length; + uint8_t *new_authtok_data;
memset(&pd, 0, sizeof(pd));
@@ -72,14 +91,12 @@ bool dp_unpack_pam_request(DBusMessage *msg, TALLOC_CTX *mem_ctx, DBUS_TYPE_STRING, &(pd.tty), DBUS_TYPE_STRING, &(pd.ruser), DBUS_TYPE_STRING, &(pd.rhost), - DBUS_TYPE_UINT32, &(pd.authtok_type), + DBUS_TYPE_UINT32, &authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd.authtok), - &(pd.authtok_size), - DBUS_TYPE_UINT32, &(pd.newauthtok_type), + &authtok_data, &authtok_length, + DBUS_TYPE_UINT32, &new_authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd.newauthtok), - &(pd.newauthtok_size), + &new_authtok_data, &new_authtok_length, DBUS_TYPE_INT32, &(pd.priv), DBUS_TYPE_UINT32, &(pd.cli_pid), DBUS_TYPE_INVALID); @@ -95,14 +112,17 @@ bool dp_unpack_pam_request(DBusMessage *msg, TALLOC_CTX *mem_ctx, return false; }
- if (pd.authtok_size != 0 && pd.authtok != NULL) { - memset(pd.authtok, 0, pd.authtok_size); - pd.authtok_size = 0; + ret = sss_authtok_set(*new_pd, &((*new_pd)->authtok), authtok_type, + authtok_data, authtok_length); + if (ret) { + DEBUG(1, ("Failed to set auth token: %d [%s]\n", ret, strerror(ret))); + return false; } - - if (pd.newauthtok_size != 0 && pd.newauthtok != NULL) { - memset(pd.newauthtok, 0, pd.newauthtok_size); - pd.newauthtok_size = 0; + ret = sss_authtok_set(*new_pd, &((*new_pd)->newauthtok), new_authtok_type, + new_authtok_data, new_authtok_length); + if (ret) { + DEBUG(1, ("Failed to set auth token: %d [%s]\n", ret, strerror(ret))); + return false; }
return true; diff --git a/src/providers/dp_pam_data_util.c b/src/providers/dp_pam_data_util.c index 889c47f00bfb49effab982ed40454b5120b84bf6..64f0d69bd0e8ebc28df958c393b40afcb5e18c31 100644 --- a/src/providers/dp_pam_data_util.c +++ b/src/providers/dp_pam_data_util.c @@ -25,26 +25,6 @@ #include "providers/data_provider.h"
-#define PD_STR_COPY(el) do { \ - if (old_pd->el != NULL) { \ - pd->el = talloc_strdup(pd, old_pd->el); \ - if (pd->el == NULL) { \ - DEBUG(1, ("talloc_strdup failed.\n")); \ - goto failed; \ - } \ - } \ -} while(0) - -#define PD_MEM_COPY(el, size) do { \ - if (old_pd->el != NULL) { \ - pd->el = talloc_memdup(pd, old_pd->el, (size)); \ - if (pd->el == NULL) { \ - DEBUG(1, ("talloc_memdup failed.\n")); \ - goto failed; \ - } \ - } \ -} while(0) - #define PAM_SAFE_ITEM(item) item ? item : "not set"
static const char *pamcmd2str(int cmd) { @@ -72,17 +52,11 @@ int pam_data_destructor(void *ptr) { struct pam_data *pd = talloc_get_type(ptr, struct pam_data);
- if (pd->authtok_size != 0 && pd->authtok != NULL) { - memset(pd->authtok, 0, pd->authtok_size); - pd->authtok_size = 0; - } + /* make sure to wipe any password from memory before freeing */ + sss_authtok_wipe_password(&pd->authtok); + sss_authtok_wipe_password(&pd->newauthtok);
- if (pd->newauthtok_size != 0 && pd->newauthtok != NULL) { - memset(pd->newauthtok, 0, pd->newauthtok_size); - pd->newauthtok_size = 0; - } - - return EOK; + return 0; }
struct pam_data *create_pam_data(TALLOC_CTX *mem_ctx) @@ -100,41 +74,72 @@ struct pam_data *create_pam_data(TALLOC_CTX *mem_ctx) return pd; }
-errno_t copy_pam_data(TALLOC_CTX *mem_ctx, struct pam_data *old_pd, - struct pam_data **new_pd) +errno_t copy_pam_data(TALLOC_CTX *mem_ctx, struct pam_data *src, + struct pam_data **dst) { struct pam_data *pd = NULL; + errno_t ret;
pd = create_pam_data(mem_ctx); if (pd == NULL) { - DEBUG(1, ("create_pam_data failed.\n")); - return ENOMEM; + ret = ENOMEM; + goto failed; }
- pd->cmd = old_pd->cmd; - pd->authtok_type = old_pd->authtok_type; - pd->authtok_size = old_pd->authtok_size; - pd->newauthtok_type = old_pd->newauthtok_type; - pd->newauthtok_size = old_pd->newauthtok_size; - pd->priv = old_pd->priv; + pd->cmd = src->cmd; + pd->priv = src->priv;
- PD_STR_COPY(domain); - PD_STR_COPY(user); - PD_STR_COPY(service); - PD_STR_COPY(tty); - PD_STR_COPY(ruser); - PD_STR_COPY(rhost); - PD_MEM_COPY(authtok, old_pd->authtok_size); - PD_MEM_COPY(newauthtok, old_pd->newauthtok_size); - pd->cli_pid = old_pd->cli_pid; + pd->domain = talloc_strdup(pd, src->domain); + if (pd->domain == NULL && src->domain != NULL) { + ret = ENOMEM; + goto failed; + } + pd->user = talloc_strdup(pd, src->user); + if (pd->user == NULL && src->user != NULL) { + ret = ENOMEM; + goto failed; + } + pd->service = talloc_strdup(pd, src->service); + if (pd->service == NULL && src->service != NULL) { + ret = ENOMEM; + goto failed; + } + pd->tty = talloc_strdup(pd, src->tty); + if (pd->tty == NULL && src->tty != NULL) { + ret = ENOMEM; + goto failed; + } + pd->ruser = talloc_strdup(pd, src->ruser); + if (pd->ruser == NULL && src->ruser != NULL) { + ret = ENOMEM; + goto failed; + } + pd->rhost = talloc_strdup(pd, src->rhost); + if (pd->rhost == NULL && src->rhost != NULL) { + ret = ENOMEM; + goto failed; + } + + pd->cli_pid = src->cli_pid; + + ret = sss_authtok_copy(pd, &src->authtok, &pd->authtok); + if (ret) { + goto failed; + } + + ret = sss_authtok_copy(pd, &src->newauthtok, &pd->newauthtok); + if (ret) { + goto failed; + }
- *new_pd = pd; + *dst = pd;
return EOK;
failed: talloc_free(pd); - return ENOMEM; + DEBUG(1, ("copy_pam_data failed: (%d) %s.\n", ret, strerror(ret))); + return ret; }
void pam_print_data(int l, struct pam_data *pd) @@ -146,10 +151,8 @@ void pam_print_data(int l, struct pam_data *pd) DEBUG(l, ("tty: %s\n", PAM_SAFE_ITEM(pd->tty))); DEBUG(l, ("ruser: %s\n", PAM_SAFE_ITEM(pd->ruser))); DEBUG(l, ("rhost: %s\n", PAM_SAFE_ITEM(pd->rhost))); - DEBUG(l, ("authtok type: %d\n", pd->authtok_type)); - DEBUG(l, ("authtok size: %d\n", pd->authtok_size)); - DEBUG(l, ("newauthtok type: %d\n", pd->newauthtok_type)); - DEBUG(l, ("newauthtok size: %d\n", pd->newauthtok_size)); + DEBUG(l, ("authtok type: %d\n", sss_authtok_get_type(&pd->authtok))); + DEBUG(l, ("newauthtok type: %d\n", sss_authtok_get_type(&pd->newauthtok))); DEBUG(l, ("priv: %d\n", pd->priv)); DEBUG(l, ("cli_pid: %d\n", pd->cli_pid)); } diff --git a/src/providers/ipa/ipa_auth.c b/src/providers/ipa/ipa_auth.c index eb62f0295cc0dc36daad9d4147556d993c7f1509..ee15afa5c83c0c68d19e169649ae6958a1553bd1 100644 --- a/src/providers/ipa/ipa_auth.c +++ b/src/providers/ipa/ipa_auth.c @@ -332,7 +332,6 @@ static void ipa_migration_flag_connect_done(struct tevent_req *req) const char **attrs; struct ldb_message *user_msg; const char *dn; - struct dp_opt_blob password; int dp_err = DP_ERR_FATAL; int ret;
@@ -374,11 +373,8 @@ static void ipa_migration_flag_connect_done(struct tevent_req *req) goto done; }
- password.data = state->pd->authtok; - password.length = state->pd->authtok_size; - req = sdap_auth_send(state, state->ev, state->sh, NULL, NULL, dn, - "password", password); + &state->pd->authtok); if (req == NULL) { DEBUG(SSSDBG_OP_FAILURE, ("sdap_auth_send failed.\n")); goto done; diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c index 5ef6cfc28625c55d850b73dc8cc621f33da1bdce..29ac482a9d277b560fa4693a4f73c898ee3d5ff2 100644 --- a/src/providers/krb5/krb5_auth.c +++ b/src/providers/krb5/krb5_auth.c @@ -278,12 +278,12 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, struct pam_data *pd, uid_t uid, int *pam_status, int *dp_err) { - char *password = NULL; + const char *password = NULL; errno_t ret;
- password = talloc_strndup(state, pd->authtok, pd->authtok_size); - if (!password) { - DEBUG(0, ("Out of memory copying password\n")); + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + if (ret != EOK) { + DEBUG(0, ("Failed to get password [%d] %s\n", ret, strerror(ret))); *pam_status = PAM_SYSTEM_ERR; *dp_err = DP_ERR_OK; return; @@ -294,7 +294,7 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, DEBUG(1, ("Offline authentication failed\n")); *pam_status = cached_login_pam_status(ret); *dp_err = DP_ERR_OK; - goto done; + return; }
ret = add_user_to_delayed_online_authentication(krb5_ctx, pd, uid); @@ -304,12 +304,6 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, } *pam_status = PAM_AUTHINFO_UNAVAIL; *dp_err = DP_ERR_OFFLINE; - -done: - if (password) { - for (i = 0; password[i]; i++) password[i] = 0; - talloc_zfree(password); - } }
static errno_t krb5_auth_prepare_ccache_file(struct krb5child_req *kr, @@ -385,16 +379,9 @@ static errno_t krb5_auth_prepare_ccache_file(struct krb5child_req *kr,
static void krb5_auth_store_creds(struct sysdb_ctx *sysdb, struct pam_data *pd) { - TALLOC_CTX *tmp_ctx; char *password = NULL; int ret = EOK;
- tmp_ctx = talloc_new(NULL); - if (!tmp_ctx) { - DEBUG(0, ("Out of memory when trying to store credentials\n")); - return; - } - switch(pd->cmd) { case SSS_CMD_RENEW: /* The authtok is set to the credential cache @@ -404,23 +391,21 @@ static void krb5_auth_store_creds(struct sysdb_ctx *sysdb, struct pam_data *pd) break; case SSS_PAM_AUTHENTICATE: case SSS_PAM_CHAUTHTOK_PRELIM: - password = talloc_size(tmp_ctx, pd->authtok_size + 1); - if (password != NULL) { - memcpy(password, pd->authtok, pd->authtok_size); - password[pd->authtok_size] = '\0'; - } + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); break; case SSS_PAM_CHAUTHTOK: - password = talloc_size(tmp_ctx, pd->newauthtok_size + 1); - if (password != NULL) { - memcpy(password, pd->newauthtok, pd->newauthtok_size); - password[pd->newauthtok_size] = '\0'; - } + ret = sss_authtok_get_password(&pd->newauthtok, &password, NULL); break; default: DEBUG(0, ("unsupported PAM command [%d].\n", pd->cmd)); }
+ if (ret != EOK) { + DEBUG(0, ("Failed to get password [%d] %s\n", ret, strerror(ret))); + /* password caching failures are not fatal errors */ + return; + } + if (password == NULL) { if (pd->cmd != SSS_CMD_RENEW) { DEBUG(0, ("password not available, offline auth may not work.\n")); @@ -430,16 +415,12 @@ static void krb5_auth_store_creds(struct sysdb_ctx *sysdb, struct pam_data *pd) return; }
- talloc_set_destructor((TALLOC_CTX *)password, password_destructor); - ret = sysdb_cache_password(sysdb, pd->user, password); if (ret) { DEBUG(2, ("Failed to cache password, offline auth may not work." " (%d)[%s]!?\n", ret, strerror(ret))); /* password caching failures are not fatal errors */ } - - talloc_zfree(tmp_ctx); }
/* krb5_auth request */ @@ -504,9 +485,17 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx, case SSS_PAM_AUTHENTICATE: case SSS_CMD_RENEW: case SSS_PAM_CHAUTHTOK: + if (sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { + DEBUG(1, ("Missing authtok for user [%s].\n", pd->user)); + state->pam_status = PAM_SYSTEM_ERR; + state->dp_err = DP_ERR_FATAL; + ret = EINVAL; + goto done; + } break; case SSS_PAM_CHAUTHTOK_PRELIM: - if (pd->priv == 1 && pd->authtok_size == 0) { + if (pd->priv == 1 && + sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { DEBUG(4, ("Password reset by root is not supported.\n")); state->pam_status = PAM_PERM_DENIED; state->dp_err = DP_ERR_OK; diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c index 66e22f4330642189370e420d0c15bce56ca537fa..d1a42d56f1cb7137f2e21b54f6959da2fec5f6d0 100644 --- a/src/providers/krb5/krb5_child.c +++ b/src/providers/krb5/krb5_child.c @@ -950,7 +950,7 @@ done: }
static krb5_error_code get_and_save_tgt(struct krb5_req *kr, - char *password) + const char *password) { krb5_error_code kerr = 0; int ret; @@ -971,7 +971,8 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr, DEBUG(SSSDBG_TRACE_FUNC, ("Attempting kinit for realm [%s]\n",realm_name)); kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - password, sss_krb5_prompter, kr, 0, + discard_const(password), + sss_krb5_prompter, kr, 0, NULL, kr->options); if (kerr != 0) { KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); @@ -1066,8 +1067,8 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) { int ret; krb5_error_code kerr = 0; - char *pass_str = NULL; - char *newpass_str = NULL; + const char *password = NULL; + const char *newpassword = NULL; int pam_status = PAM_SYSTEM_ERR; int result_code = -1; krb5_data result_code_string; @@ -1082,20 +1083,15 @@ static errno_t changepw_child(int fd, struct krb5_req *kr)
DEBUG(SSSDBG_TRACE_LIBS, ("Password change operation\n"));
- if (kr->pd->authtok_type != SSS_AUTHTOK_TYPE_PASSWORD) { + ret = sss_authtok_get_password(&kr->pd->authtok, &password, NULL); + if (ret != EOK) { + DEBUG(1, ("Failed to fetch current password [%d] %s.\n", + ret, strerror(ret))); pam_status = PAM_CRED_INSUFFICIENT; kerr = KRB5KRB_ERR_GENERIC; goto sendresponse; }
- pass_str = talloc_strndup(kr, (const char *) kr->pd->authtok, - kr->pd->authtok_size); - if (pass_str == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - kerr = KRB5KRB_ERR_GENERIC; - goto sendresponse; - } - if (kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) { /* We do not need a password expiration warning here. */ prompter = NULL; @@ -1112,7 +1108,8 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) DEBUG(SSSDBG_TRACE_FUNC, ("Attempting kinit for realm [%s]\n",realm_name)); kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - pass_str, prompter, kr, 0, + discard_const(password), + prompter, kr, 0, SSSD_KRB5_CHANGEPW_PRINCIPAL, chagepw_options); sss_krb5_get_init_creds_opt_free(kr->ctx, chagepw_options); @@ -1121,9 +1118,7 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) goto sendresponse; }
- memset(pass_str, 0, kr->pd->authtok_size); - talloc_zfree(pass_str); - memset(kr->pd->authtok, 0, kr->pd->authtok_size); + sss_authtok_set_empty(&kr->pd->authtok);
if (kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) { DEBUG(SSSDBG_TRACE_LIBS, @@ -1134,17 +1129,18 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) goto sendresponse; }
- newpass_str = talloc_strndup(kr, (const char *) kr->pd->newauthtok, - kr->pd->newauthtok_size); - if (newpass_str == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); + ret = sss_authtok_get_password(&kr->pd->newauthtok, &newpassword, NULL); + if (ret != EOK) { + DEBUG(1, ("Failed to fetch new password [%d] %s.\n", + ret, strerror(ret))); kerr = KRB5KRB_ERR_GENERIC; goto sendresponse; }
memset(&result_code_string, 0, sizeof(krb5_data)); memset(&result_string, 0, sizeof(krb5_data)); - kerr = krb5_change_password(kr->ctx, kr->creds, newpass_str, &result_code, + kerr = krb5_change_password(kr->ctx, kr->creds, + discard_const(newpassword), &result_code, &result_code_string, &result_string);
if (kerr == KRB5_KDC_UNREACH) { @@ -1200,10 +1196,9 @@ static errno_t changepw_child(int fd, struct krb5_req *kr)
krb5_free_cred_contents(kr->ctx, kr->creds);
- kerr = get_and_save_tgt(kr, newpass_str); - memset(newpass_str, 0, kr->pd->newauthtok_size); - talloc_zfree(newpass_str); - memset(kr->pd->newauthtok, 0, kr->pd->newauthtok_size); + kerr = get_and_save_tgt(kr, newpassword); + + sss_authtok_set_empty(&kr->pd->newauthtok);
pam_status = kerr_to_status(kerr);
@@ -1220,28 +1215,21 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) { int ret; krb5_error_code kerr = 0; - char *pass_str = NULL; + const char *password = NULL; int pam_status = PAM_SYSTEM_ERR; krb5_get_init_creds_opt *chagepw_options;
DEBUG(SSSDBG_TRACE_LIBS, ("Attempting to get a TGT\n"));
- if (kr->pd->authtok_type != SSS_AUTHTOK_TYPE_PASSWORD) { + ret = sss_authtok_get_password(&kr->pd->authtok, &password, NULL); + if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Unknown authtok type\n")); pam_status = PAM_CRED_INSUFFICIENT; kerr = KRB5KRB_ERR_GENERIC; goto sendresponse; }
- pass_str = talloc_strndup(kr, (const char *) kr->pd->authtok, - kr->pd->authtok_size); - if (pass_str == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - kerr = KRB5KRB_ERR_GENERIC; - goto sendresponse; - } - - kerr = get_and_save_tgt(kr, pass_str); + kerr = get_and_save_tgt(kr, password);
/* If the password is expired the KDC will always return KRB5KDC_ERR_KEY_EXP regardless if the supplied password is correct or @@ -1264,7 +1252,8 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) }
kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - pass_str, sss_krb5_prompter, kr, 0, + discard_const(password), + sss_krb5_prompter, kr, 0, SSSD_KRB5_CHANGEPW_PRINCIPAL, chagepw_options);
@@ -1276,9 +1265,7 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) } }
- memset(pass_str, 0, kr->pd->authtok_size); - talloc_zfree(pass_str); - memset(kr->pd->authtok, 0, kr->pd->authtok_size); + sss_authtok_set_empty(&kr->pd->authtok);
pam_status = kerr_to_status(kerr);
@@ -1333,25 +1320,20 @@ static errno_t renew_tgt_child(int fd, struct krb5_req *kr) int ret; int status = PAM_AUTHTOK_ERR; int kerr; - char *ccname; + const char *ccname; krb5_ccache ccache = NULL;
DEBUG(SSSDBG_TRACE_LIBS, ("Renewing a ticket\n"));
- if (kr->pd->authtok_type != SSS_AUTHTOK_TYPE_CCFILE) { - DEBUG(1, ("Unsupported authtok type for TGT renewal [%d].\n", - kr->pd->authtok_type)); + ret = sss_authtok_get_ccfile(&kr->pd->authtok, &ccname, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + ("Unsupported authtok type for TGT renewal [%d].\n", + sss_authtok_get_type(&kr->pd->authtok))); kerr = EINVAL; goto done; }
- ccname = talloc_strndup(kr, (char *) kr->pd->authtok, kr->pd->authtok_size); - if (ccname == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - kerr = ENOMEM; - goto done; - } - kerr = krb5_cc_resolve(kr->ctx, ccname, &ccache); if (kerr != 0) { KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); @@ -1444,6 +1426,38 @@ static errno_t create_empty_ccache(int fd, struct krb5_req *kr) return ret; }
+static errno_t unpack_authtok(TALLOC_CTX *mem_ctx, struct sss_auth_token *tok, + uint8_t *buf, size_t size, size_t *p) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + errno_t ret = EOK; + + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, buf + *p, size, p); + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_length, buf + *p, size, p); + if ((*p + auth_token_length) > size) { + return EINVAL; + } + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_set_password(mem_ctx, tok, (char *)(buf + *p), 0); + break; + case SSS_AUTHTOK_TYPE_CCFILE: + ret = sss_authtok_set_ccfile(mem_ctx, tok, (char *)(buf + *p), 0); + break; + default: + return EINVAL; + } + + if (ret == EOK) { + *p += auth_token_length; + } + return ret; +} + static errno_t unpack_buffer(uint8_t *buf, size_t size, struct pam_data *pd, struct krb5_req *kr, uint32_t *offline) { @@ -1451,6 +1465,7 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size, struct pam_data *pd, uint32_t len; uint32_t validate; uint32_t different_realm; + errno_t ret;
DEBUG(SSSDBG_TRACE_LIBS, ("total buffer size: [%d]\n", size));
@@ -1491,35 +1506,26 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size, struct pam_data *pd, if (kr->keytab == NULL) return ENOMEM; p += len;
- SAFEALIGN_COPY_UINT32_CHECK(&pd->authtok_type, buf + p, size, &p); - SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p); - if ((p + len) > size) return EINVAL; - pd->authtok = (uint8_t *)talloc_strndup(pd, (char *)(buf + p), len); - if (pd->authtok == NULL) return ENOMEM; - pd->authtok_size = len + 1; - p += len; + ret = unpack_authtok(pd, &pd->authtok, buf, size, &p); + if (ret) { + return ret; + }
DEBUG(SSSDBG_CONF_SETTINGS, ("ccname: [%s] keytab: [%s]\n", kr->ccname, kr->keytab)); } else { kr->ccname = NULL; kr->keytab = NULL; - pd->authtok = NULL; - pd->authtok_size = 0; + sss_authtok_set_empty(&pd->authtok); }
if (pd->cmd == SSS_PAM_CHAUTHTOK) { - SAFEALIGN_COPY_UINT32_CHECK(&pd->newauthtok_type, buf + p, size, &p); - SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p); - - if ((p + len) > size) return EINVAL; - pd->newauthtok = (uint8_t *)talloc_strndup(pd, (char *)(buf + p), len); - if (pd->newauthtok == NULL) return ENOMEM; - pd->newauthtok_size = len + 1; - p += len; + ret = unpack_authtok(pd, &pd->newauthtok, buf, size, &p); + if (ret) { + return ret; + } } else { - pd->newauthtok = NULL; - pd->newauthtok_size = 0; + sss_authtok_set_empty(&pd->newauthtok); }
if (pd->cmd == SSS_PAM_ACCT_MGMT) { diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c index e792db3f7a6ebe7857b1ec699bc37d52ae3cad5d..5adbcf700ebf02a2aa524af3cecab51e543b4986 100644 --- a/src/providers/krb5/krb5_child_handler.c +++ b/src/providers/krb5/krb5_child_handler.c @@ -85,6 +85,43 @@ static int child_io_destructor(void *ptr) return EOK; }
+static errno_t pack_authtok(struct io_buffer *buf, size_t *rp, + struct sss_auth_token *tok) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + const char *data; + size_t len; + errno_t ret = EOK; + + auth_token_type = sss_authtok_get_type(tok); + + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + auth_token_length = 0; + data = ""; + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_get_password(tok, &data, &len); + auth_token_length = len + 1; + break; + case SSS_AUTHTOK_TYPE_CCFILE: + ret = sss_authtok_get_password(tok, &data, &len); + auth_token_length = len + 1; + break; + default: + ret = EINVAL; + } + + if (ret == EOK) { + SAFEALIGN_COPY_UINT32(&buf->data[*rp], &auth_token_type, rp); + SAFEALIGN_COPY_UINT32(&buf->data[*rp], &auth_token_length, rp); + safealign_memcpy(&buf->data[*rp], data, auth_token_length, rp); + } + + return ret; +} + static errno_t create_send_buffer(struct krb5child_req *kr, struct io_buffer **io_buf) { @@ -94,6 +131,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr, uint32_t validate; uint32_t different_realm; size_t username_len = 0; + errno_t ret;
keytab = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_KEYTAB); if (keytab == NULL) { @@ -117,11 +155,12 @@ static errno_t create_send_buffer(struct krb5child_req *kr, kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM || kr->pd->cmd == SSS_PAM_CHAUTHTOK) { buf->size += 4*sizeof(uint32_t) + strlen(kr->ccname) + strlen(keytab) + - kr->pd->authtok_size; + sss_authtok_get_size(&kr->pd->authtok); }
if (kr->pd->cmd == SSS_PAM_CHAUTHTOK) { - buf->size += 2*sizeof(uint32_t) + kr->pd->newauthtok_size; + buf->size += 2*sizeof(uint32_t) + + sss_authtok_get_size(&kr->pd->newauthtok); }
if (kr->pd->cmd == SSS_PAM_ACCT_MGMT) { @@ -157,17 +196,17 @@ static errno_t create_send_buffer(struct krb5child_req *kr, SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(keytab), &rp); safealign_memcpy(&buf->data[rp], keytab, strlen(keytab), &rp);
- SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->authtok_type, &rp); - SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->authtok_size, &rp); - safealign_memcpy(&buf->data[rp], kr->pd->authtok, - kr->pd->authtok_size, &rp); + ret = pack_authtok(buf, &rp, &kr->pd->authtok); + if (ret) { + return ret; + } }
if (kr->pd->cmd == SSS_PAM_CHAUTHTOK) { - SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->newauthtok_type, &rp); - SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->newauthtok_size, &rp); - safealign_memcpy(&buf->data[rp], kr->pd->newauthtok, - kr->pd->newauthtok_size, &rp); + ret = pack_authtok(buf, &rp, &kr->pd->newauthtok); + if (ret) { + return ret; + } }
if (kr->pd->cmd == SSS_PAM_ACCT_MGMT) { diff --git a/src/providers/krb5/krb5_delayed_online_authentication.c b/src/providers/krb5/krb5_delayed_online_authentication.c index d5dea3bb4c7661f45b6bea83cf803c7d681062cc..f95fa634c34ebee37bffb785abe4ef5b35318a82 100644 --- a/src/providers/krb5/krb5_delayed_online_authentication.c +++ b/src/providers/krb5/krb5_delayed_online_authentication.c @@ -71,27 +71,29 @@ static void authenticate_user(struct tevent_context *ev,
DEBUG_PAM_DATA(9, pd);
- if (pd->authtok == NULL || pd->authtok_size == 0) { - DEBUG(1, ("Missing authtok for user [%s].\n", pd->user)); - return; - } - #ifdef USE_KEYRING + char *password; long keysize; long keyrevoke; - int ret; - keysize = keyctl_read(pd->key_serial, (char *) pd->authtok, - pd->authtok_size); - keyrevoke = keyctl_revoke(pd->key_serial); + errno_t ret; + + keysize = keyctl_read_alloc(pd->key_serial, (void **)&password); if (keysize == -1) { ret = errno; DEBUG(1, ("keyctl_read failed [%d][%s].\n", ret, strerror(ret))); return; - } else if (keysize != pd->authtok_size) { - DEBUG(1, ("keyctl_read returned key with wrong size, " - "expect [%d] got [%d].\n", pd->authtok_size, keysize)); + } + + ret = sss_authtok_set_password(pd, &pd->authtok, password, keysize); + safezero(password, keysize); + free(password); + if (ret) { + DEBUG(1, ("failed to set password in auth token [%d][%s].\n", + ret, strerror(ret))); return; } + + keyrevoke = keyctl_revoke(pd->key_serial); if (keyrevoke == -1) { ret = errno; DEBUG(1, ("keyctl_revoke failed [%d][%s].\n", ret, strerror(ret))); @@ -244,8 +246,8 @@ errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx, return EINVAL; }
- if (pd->authtok_size == 0 || pd->authtok == NULL) { - DEBUG(1, ("Missing authtok for user [%s].\n", pd->user)); + if (sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { + DEBUG(1, ("Invalid authtok for user [%s].\n", pd->user)); return EINVAL; }
@@ -257,17 +259,29 @@ errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx,
#ifdef USE_KEYRING - new_pd->key_serial = add_key("user", new_pd->user, new_pd->authtok, - new_pd->authtok_size, KEY_SPEC_SESSION_KEYRING); + const char *password; + size_t len; + + ret = sss_authtok_get_password(&new_pd->authtok, &password, &len); + if (ret) { + DEBUG(1, ("Failed to get password [%d][%s].\n", ret, strerror(ret))); + sss_authtok_set_empty(&new_pd->authtok); + talloc_free(new_pd); + return ret; + } + + new_pd->key_serial = add_key("user", new_pd->user, password, len, + KEY_SPEC_SESSION_KEYRING); if (new_pd->key_serial == -1) { ret = errno; - DEBUG(1, ("add_key fialed [%d][%s].\n", ret, strerror(ret))); + DEBUG(1, ("add_key failed [%d][%s].\n", ret, strerror(ret))); + sss_authtok_set_empty(&new_pd->authtok); talloc_free(new_pd); return ret; } DEBUG(9, ("Saved authtok of user [%s] with serial [%ld].\n", new_pd->user, new_pd->key_serial)); - memset(new_pd->authtok, 0, new_pd->authtok_size); + sss_authtok_set_empty(&new_pd->authtok); #endif
key.type = HASH_KEY_ULONG; diff --git a/src/providers/krb5/krb5_renew_tgt.c b/src/providers/krb5/krb5_renew_tgt.c index ccb7e6af6d05121292d1152977c319daf660c9ef..4a812ab04d028961914557522423be82a1a01941 100644 --- a/src/providers/krb5/krb5_renew_tgt.c +++ b/src/providers/krb5/krb5_renew_tgt.c @@ -593,22 +593,14 @@ errno_t add_tgt_to_renew_table(struct krb5_ctx *krb5_ctx, const char *ccfile, goto done; }
- if (renew_data->pd->newauthtok_type != SSS_AUTHTOK_TYPE_EMPTY) { - talloc_zfree(renew_data->pd->newauthtok); - renew_data->pd->newauthtok_size = 0; - renew_data->pd->newauthtok_type = SSS_AUTHTOK_TYPE_EMPTY; - } + sss_authtok_set_empty(&renew_data->pd->newauthtok);
- talloc_zfree(renew_data->pd->authtok); - renew_data->pd->authtok = (uint8_t *) talloc_strdup(renew_data->pd, - renew_data->ccfile); - if (renew_data->pd->authtok == NULL) { - DEBUG(1, ("talloc_strdup failed.\n")); - ret = ENOMEM; + ret = sss_authtok_set_ccfile(renew_data->pd, &renew_data->pd->authtok, + renew_data->ccfile, 0); + if (ret) { + DEBUG(1, ("Failed to store ccfile in auth token.\n")); goto done; } - renew_data->pd->authtok_size = strlen((char *) renew_data->pd->authtok) + 1; - renew_data->pd->authtok_type = SSS_AUTHTOK_TYPE_CCFILE;
renew_data->pd->cmd = SSS_CMD_RENEW;
diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c index 32a2e04ea959a3cc81b88f5b2b19575c813e8adf..98483fee0da418523e78152861d489988eb9c6c2 100644 --- a/src/providers/ldap/ldap_auth.c +++ b/src/providers/ldap/ldap_auth.c @@ -462,7 +462,7 @@ struct auth_state { struct tevent_context *ev; struct sdap_auth_ctx *ctx; const char *username; - struct dp_opt_blob password; + struct sss_auth_token *authtok; struct sdap_service *sdap_service;
struct sdap_handle *sh; @@ -484,7 +484,7 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx, struct tevent_context *ev, struct sdap_auth_ctx *ctx, const char *username, - struct dp_opt_blob password, + struct sss_auth_token *authtok, bool try_chpass_service) { struct tevent_req *req; @@ -493,8 +493,8 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx, req = tevent_req_create(memctx, &state, struct auth_state); if (!req) return NULL;
- /* Treat a zero-length password as a failure */ - if (password.length == 0) { + /* The token must be a password token */ + if (sss_authtok_get_type(authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { state->result = SDAP_AUTH_FAILED; tevent_req_done(req); return tevent_req_post(req, ev); @@ -503,7 +503,7 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx, state->ev = ev; state->ctx = ctx; state->username = username; - state->password = password; + state->authtok = authtok; state->srv = NULL; if (try_chpass_service && ctx->chpass_service != NULL && ctx->chpass_service->name != NULL) { @@ -632,7 +632,7 @@ static void auth_connect_done(struct tevent_req *subreq)
subreq = sdap_auth_send(state, state->ev, state->sh, NULL, NULL, state->dn, - "password", state->password); + state->authtok); if (!subreq) { tevent_req_error(req, ENOMEM); return; @@ -727,8 +727,6 @@ struct sdap_pam_chpass_state { struct pam_data *pd; const char *username; char *dn; - char *password; - char *new_password; struct sdap_handle *sh;
struct sdap_auth_ctx *ctx; @@ -744,7 +742,6 @@ void sdap_pam_chpass_handler(struct be_req *breq) struct sdap_auth_ctx *ctx; struct tevent_req *subreq; struct pam_data *pd; - struct dp_opt_blob authtok; int dp_err = DP_ERR_FATAL;
ctx = talloc_get_type(breq->be_ctx->bet_info[BET_CHPASS].pvt_bet_data, @@ -758,8 +755,8 @@ void sdap_pam_chpass_handler(struct be_req *breq) goto done; }
- if (pd->priv == 1 && pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM && - pd->authtok_size == 0) { + if ((pd->priv == 1) && (pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) && + (sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD)) { DEBUG(4, ("Password reset by root is not supported.\n")); pd->pam_status = PAM_PERM_DENIED; dp_err = DP_ERR_OK; @@ -782,25 +779,9 @@ void sdap_pam_chpass_handler(struct be_req *breq) state->pd = pd; state->username = pd->user; state->ctx = ctx; - state->password = talloc_strndup(state, - (char *)pd->authtok, pd->authtok_size); - if (!state->password) goto done; - talloc_set_destructor((TALLOC_CTX *)state->password, - password_destructor);
- if (pd->cmd == SSS_PAM_CHAUTHTOK) { - state->new_password = talloc_strndup(state, - (char *)pd->newauthtok, - pd->newauthtok_size); - if (!state->new_password) goto done; - talloc_set_destructor((TALLOC_CTX *)state->new_password, - password_destructor); - } - - authtok.data = (uint8_t *)state->password; - authtok.length = strlen(state->password); - subreq = auth_send(breq, breq->be_ctx->ev, - ctx, state->username, authtok, true); + subreq = auth_send(breq, breq->be_ctx->ev, ctx, + state->username, &pd->authtok, true); if (!subreq) goto done;
tevent_req_set_callback(subreq, sdap_auth4chpass_done, state); @@ -887,18 +868,30 @@ static void sdap_auth4chpass_done(struct tevent_req *req) state->pd->pam_status = PAM_MODULE_UNKNOWN; goto done; } else { + const char *password; + const char *new_password; + + ret = sss_authtok_get_password(&state->pd->authtok, + &password, NULL); + if (ret) { + state->pd->pam_status = PAM_SYSTEM_ERR; + goto done; + } + ret = sss_authtok_get_password(&state->pd->newauthtok, + &new_password, NULL); + if (ret) { + state->pd->pam_status = PAM_SYSTEM_ERR; + goto done; + } + subreq = sdap_exop_modify_passwd_send(state, state->breq->be_ctx->ev, - state->sh, - state->dn, - state->password, - state->new_password); - + state->sh, state->dn, + password, new_password); if (!subreq) { DEBUG(2, ("Failed to change password for %s\n", state->username)); goto done; } - tevent_req_set_callback(subreq, sdap_pam_chpass_done, state); return; } @@ -1013,8 +1006,6 @@ done: struct sdap_pam_auth_state { struct be_req *breq; struct pam_data *pd; - const char *username; - struct dp_opt_blob password; };
static void sdap_pam_auth_done(struct tevent_req *req); @@ -1049,12 +1040,9 @@ void sdap_pam_auth_handler(struct be_req *breq)
state->breq = breq; state->pd = pd; - state->username = pd->user; - state->password.data = pd->authtok; - state->password.length = pd->authtok_size;
subreq = auth_send(breq, breq->be_ctx->ev, ctx, - state->username, state->password, + pd->user, &pd->authtok, pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM ? true : false); if (!subreq) goto done;
@@ -1088,6 +1076,7 @@ static void sdap_pam_auth_done(struct tevent_req *req) enum pwexpire pw_expire_type; struct be_ctx *be_ctx = state->breq->be_ctx; void *pw_expire_data; + const char *password; int dp_err = DP_ERR_OK; int ret;
@@ -1170,26 +1159,19 @@ static void sdap_pam_auth_done(struct tevent_req *req) if (result == SDAP_AUTH_SUCCESS && state->breq->be_ctx->domain->cache_credentials) {
- char *password = talloc_strndup(state, (char *) - state->password.data, - state->password.length); - /* password caching failures are not fatal errors */ - if (!password) { - DEBUG(2, ("Failed to cache password for %s\n", state->username)); - goto done; + ret = sss_authtok_get_password(&state->pd->authtok, &password, NULL); + if (ret == EOK) { + ret = sysdb_cache_password(state->breq->be_ctx->sysdb, + state->pd->user, password); } - talloc_set_destructor((TALLOC_CTX *)password, password_destructor); - - ret = sysdb_cache_password(state->breq->be_ctx->sysdb, - state->username, password);
/* password caching failures are not fatal errors */ if (ret != EOK) { DEBUG(2, ("Failed to cache password for %s\n", - state->username)); + state->pd->user)); } else { DEBUG(4, ("Password successfully cached for %s\n", - state->username)); + state->pd->user)); } goto done; } diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c index e0440625d279fbbaa1cc2e6343b73f5a247371f7..84497b75ef586b58e27cc4dc9e6b8b3244464676 100644 --- a/src/providers/ldap/sdap_async.c +++ b/src/providers/ldap/sdap_async.c @@ -502,8 +502,8 @@ struct tevent_req *sdap_exop_modify_passwd_send(TALLOC_CTX *memctx, struct tevent_context *ev, struct sdap_handle *sh, char *user_dn, - char *password, - char *new_password) + const char *password, + const char *new_password) { struct tevent_req *req = NULL; struct sdap_exop_modify_passwd_state *state; diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h index 8c16d94e6486336e92b6112cd8b5a2dff4c97957..c5dc17037cd6d2c4ae88aa60d43d517eb2958085 100644 --- a/src/providers/ldap/sdap_async.h +++ b/src/providers/ldap/sdap_async.h @@ -108,8 +108,7 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, const char *sasl_mech, const char *sasl_user, const char *user_dn, - const char *authtok_type, - struct dp_opt_blob authtok); + struct sss_auth_token *authtok);
int sdap_auth_recv(struct tevent_req *req, TALLOC_CTX *memctx, @@ -128,8 +127,8 @@ struct tevent_req *sdap_exop_modify_passwd_send(TALLOC_CTX *memctx, struct tevent_context *ev, struct sdap_handle *sh, char *user_dn, - char *password, - char *new_password); + const char *password, + const char *new_password); int sdap_exop_modify_passwd_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, enum sdap_result *result, char **user_error_msg); diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c index ff99248433026608f06fc548824fa2dd25aaacaa..da50f4ad49ab4319b309cf6861f801014ac47102 100644 --- a/src/providers/ldap/sdap_async_connection.c +++ b/src/providers/ldap/sdap_async_connection.c @@ -493,7 +493,7 @@ static struct tevent_req *simple_bind_send(TALLOC_CTX *memctx, DEBUG(4, ("Executing simple bind as: %s\n", state->user_dn));
ret = ldap_sasl_bind(state->sh->ldap, state->user_dn, LDAP_SASL_SIMPLE, - state->pw, request_controls, NULL, &msgid); + pw, request_controls, NULL, &msgid); if (ctrls[0]) ldap_control_free(ctrls[0]); if (ret == -1 || msgid == -1) { ret = ldap_get_option(state->sh->ldap, @@ -1082,18 +1082,12 @@ int sdap_kinit_recv(struct tevent_req *req, /* ==Authenticaticate-User-by-DN========================================== */
struct sdap_auth_state { - const char *user_dn; - struct berval pw; struct sdap_ppolicy_data *ppolicy; - - int result; bool is_sasl; + int result; };
static void sdap_auth_done(struct tevent_req *subreq); -static int sdap_auth_get_authtok(const char *authtok_type, - struct dp_opt_blob authtok, - struct berval *pw);
/* TODO: handle sasl_cred */ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, @@ -1102,31 +1096,14 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, const char *sasl_mech, const char *sasl_user, const char *user_dn, - const char *authtok_type, - struct dp_opt_blob authtok) + struct sss_auth_token *authtok) { struct tevent_req *req, *subreq; struct sdap_auth_state *state; - int ret;
req = tevent_req_create(memctx, &state, struct sdap_auth_state); if (!req) return NULL;
- state->user_dn = user_dn; - - ret = sdap_auth_get_authtok(authtok_type, authtok, &state->pw); - if (ret != EOK) { - if (ret == ENOSYS) { - DEBUG(1, ("Getting authtok is not supported with the " - "crypto library compiled with, authentication " - "might fail!\n")); - } else { - DEBUG(1, ("Cannot parse authtok.\n")); - tevent_req_error(req, ret); - return tevent_req_post(req, ev); - } - } - if (sasl_mech) { state->is_sasl = true; subreq = sasl_bind_send(state, ev, sh, sasl_mech, sasl_user, NULL); @@ -1135,8 +1112,27 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, return tevent_req_post(req, ev); } } else { + const char *password = NULL; + struct berval pw; + size_t pwlen; + errno_t ret; + + ret = sss_authtok_get_password(authtok, &password, &pwlen); + if (ret != EOK) { + DEBUG(1, ("Cannot parse authtok.\n")); + tevent_req_error(req, ret); + return tevent_req_post(req, ev); + } + /* Treat a zero-length password as a failure */ + if (*password == '\0') { + tevent_req_error(req, ENOENT); + return tevent_req_post(req, ev); + } + pw.bv_val = discard_const(password); + pw.bv_len = pwlen - 1; + state->is_sasl = false; - subreq = simple_bind_send(state, ev, sh, user_dn, &state->pw); + subreq = simple_bind_send(state, ev, sh, user_dn, &pw); if (!subreq) { tevent_req_error(req, ENOMEM); return tevent_req_post(req, ev); @@ -1598,6 +1594,10 @@ static void sdap_cli_auth_step(struct tevent_req *req) SDAP_SASL_MECH); const char *user_dn = dp_opt_get_string(state->opts->basic, SDAP_DEFAULT_BIND_DN); + const char *authtok_type; + struct dp_opt_blob authtok_blob; + struct sss_auth_token authtok = { 0 }; + errno_t ret;
/* Set the LDAP expiration time * If SASL has already set it, use the sooner of the two @@ -1620,17 +1620,31 @@ static void sdap_cli_auth_step(struct tevent_req *req) return; }
- subreq = sdap_auth_send(state, - state->ev, - state->sh, - sasl_mech, + authtok_type = dp_opt_get_string(state->opts->basic, + SDAP_DEFAULT_AUTHTOK_TYPE); + if (authtok_type != NULL) { + if (strcasecmp(authtok_type, "password") != 0) { + DEBUG(SSSDBG_TRACE_LIBS, ("Invalid authtoken type\n")); + tevent_req_error(req, EINVAL); + return; + } + authtok_blob = dp_opt_get_blob(state->opts->basic, + SDAP_DEFAULT_AUTHTOK); + + ret = sss_authtok_set_password(state, &authtok, + (const char *)authtok_blob.data, + authtok_blob.length); + if (ret) { + tevent_req_error(req, ret); + return; + } + } + + subreq = sdap_auth_send(state, state->ev, + state->sh, sasl_mech, dp_opt_get_string(state->opts->basic, - SDAP_SASL_AUTHID), - user_dn, - dp_opt_get_string(state->opts->basic, - SDAP_DEFAULT_AUTHTOK_TYPE), - dp_opt_get_blob(state->opts->basic, - SDAP_DEFAULT_AUTHTOK)); + SDAP_SASL_AUTHID), + user_dn, &authtok); if (!subreq) { tevent_req_error(req, ENOMEM); return; diff --git a/src/providers/proxy/proxy.h b/src/providers/proxy/proxy.h index cea03382517231cdf2b96069ab93dfb7967b46a6..962cb28fc7d6362c45d268f289ffbce103a6e738 100644 --- a/src/providers/proxy/proxy.h +++ b/src/providers/proxy/proxy.h @@ -89,11 +89,8 @@ struct proxy_nss_ops { };
struct authtok_conv { - uint32_t authtok_size; - uint8_t *authtok; - - uint32_t newauthtok_size; - uint8_t *newauthtok; + struct sss_auth_token authtok; + struct sss_auth_token newauthtok;
bool sent_old; }; diff --git a/src/providers/proxy/proxy_auth.c b/src/providers/proxy/proxy_auth.c index 8088283fa8147f75b7d8eb4c83c63208163c9375..3430f38b282eff2da24735f8d635a952edde8888 100644 --- a/src/providers/proxy/proxy_auth.c +++ b/src/providers/proxy/proxy_auth.c @@ -712,7 +712,7 @@ static void proxy_child_done(struct tevent_req *req) struct proxy_client_ctx *client_ctx = tevent_req_callback_data(req, struct proxy_client_ctx); struct pam_data *pd = NULL; - char *password; + const char *password; int ret; struct tevent_immediate *imm;
@@ -747,17 +747,15 @@ static void proxy_child_done(struct tevent_req *req)
/* Check if we need to save the cached credentials */ if ((pd->cmd == SSS_PAM_AUTHENTICATE || pd->cmd == SSS_PAM_CHAUTHTOK) && - pd->pam_status == PAM_SUCCESS && - client_ctx->be_req->be_ctx->domain->cache_credentials) { - password = talloc_strndup(client_ctx->be_req, - (char *) pd->authtok, - pd->authtok_size); - if (!password) { + (pd->pam_status == PAM_SUCCESS) && + client_ctx->be_req->be_ctx->domain->cache_credentials) { + + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + if (ret) { /* password caching failures are not fatal errors */ DEBUG(2, ("Failed to cache password\n")); goto done; } - talloc_set_destructor((TALLOC_CTX *)password, password_destructor);
ret = sysdb_cache_password(client_ctx->be_req->be_ctx->sysdb, pd->user, password); diff --git a/src/providers/proxy/proxy_child.c b/src/providers/proxy/proxy_child.c index c575948a7036d9b73d93bd00e111834b12d28e7d..556dbf9b5488d75f0fa60386958f61b95d61fba2 100644 --- a/src/providers/proxy/proxy_child.c +++ b/src/providers/proxy/proxy_child.c @@ -80,6 +80,9 @@ static int proxy_internal_conv(int num_msg, const struct pam_message **msgm, int i; struct pam_response *reply; struct authtok_conv *auth_data; + const char *password; + size_t pwlen; + errno_t ret;
auth_data = talloc_get_type(appdata_ptr, struct authtok_conv);
@@ -94,11 +97,13 @@ static int proxy_internal_conv(int num_msg, const struct pam_message **msgm, case PAM_PROMPT_ECHO_OFF: DEBUG(4, ("Conversation message: [%s]\n", msgm[i]->msg)); reply[i].resp_retcode = 0; - reply[i].resp = calloc(auth_data->authtok_size + 1, - sizeof(char)); + + ret = sss_authtok_get_password(&auth_data->authtok, + &password, &pwlen); + if (ret) goto failed; + reply[i].resp = calloc(pwlen + 1, sizeof(char)); if (reply[i].resp == NULL) goto failed; - memcpy(reply[i].resp, auth_data->authtok, - auth_data->authtok_size); + memcpy(reply[i].resp, password, pwlen + 1);
break; default: @@ -124,6 +129,9 @@ static int proxy_chauthtok_conv(int num_msg, const struct pam_message **msgm, int i; struct pam_response *reply; struct authtok_conv *auth_data; + const char *password; + size_t pwlen; + errno_t ret;
auth_data = talloc_get_type(appdata_ptr, struct authtok_conv);
@@ -141,20 +149,23 @@ static int proxy_chauthtok_conv(int num_msg, const struct pam_message **msgm, reply[i].resp_retcode = 0; if (!auth_data->sent_old) { /* The first prompt will be asking for the old authtok */ - reply[i].resp = calloc(auth_data->authtok_size + 1, - sizeof(char)); + ret = sss_authtok_get_password(&auth_data->authtok, + &password, &pwlen); + if (ret) goto failed; + reply[i].resp = calloc(pwlen + 1, sizeof(char)); if (reply[i].resp == NULL) goto failed; - memcpy(reply[i].resp, auth_data->authtok, - auth_data->authtok_size); + memcpy(reply[i].resp, password, pwlen + 1); auth_data->sent_old = true; } else { /* Subsequent prompts are looking for the new authtok */ - reply[i].resp = calloc(auth_data->newauthtok_size + 1, - sizeof(char)); + ret = sss_authtok_get_password(&auth_data->newauthtok, + &password, &pwlen); + if (ret) goto failed; + reply[i].resp = calloc(pwlen + 1, sizeof(char)); if (reply[i].resp == NULL) goto failed; - memcpy(reply[i].resp, auth_data->newauthtok, - auth_data->newauthtok_size); + memcpy(reply[i].resp, password, pwlen + 1); + auth_data->sent_old = true; }
break; @@ -213,8 +224,8 @@ static errno_t call_pam_stack(const char *pam_target, struct pam_data *pd) } switch (pd->cmd) { case SSS_PAM_AUTHENTICATE: - auth_data->authtok_size = pd->authtok_size; - auth_data->authtok = pd->authtok; + sss_authtok_copy(auth_data, &pd->authtok, + &auth_data->authtok); pam_status = pam_authenticate(pamh, 0); break; case SSS_PAM_SETCRED: @@ -230,21 +241,21 @@ static errno_t call_pam_stack(const char *pam_target, struct pam_data *pd) pam_status=pam_close_session(pamh, 0); break; case SSS_PAM_CHAUTHTOK: - auth_data->authtok_size = pd->authtok_size; - auth_data->authtok = pd->authtok; + sss_authtok_copy(auth_data, &pd->authtok, + &auth_data->authtok); if (pd->priv != 1) { pam_status = pam_authenticate(pamh, 0); auth_data->sent_old = false; if (pam_status != PAM_SUCCESS) break; } - auth_data->newauthtok_size = pd->newauthtok_size; - auth_data->newauthtok = pd->newauthtok; + sss_authtok_copy(auth_data, &pd->newauthtok, + &auth_data->newauthtok); pam_status = pam_chauthtok(pamh, 0); break; case SSS_PAM_CHAUTHTOK_PRELIM: if (pd->priv != 1) { - auth_data->authtok_size = pd->authtok_size; - auth_data->authtok = pd->authtok; + sss_authtok_copy(auth_data, &pd->authtok, + &auth_data->authtok); pam_status = pam_authenticate(pamh, 0); } else { pam_status = PAM_SUCCESS; diff --git a/src/responder/pam/pam_LOCAL_domain.c b/src/responder/pam/pam_LOCAL_domain.c index 71446b4f8da53bfe4c0707621fafb228da5f808c..23eb7a2a8ddd3ae4480030633be867564b7f59f2 100644 --- a/src/responder/pam/pam_LOCAL_domain.c +++ b/src/responder/pam/pam_LOCAL_domain.c @@ -154,22 +154,19 @@ static void do_pam_acct_mgmt(struct LOCAL_request *lreq) static void do_pam_chauthtok(struct LOCAL_request *lreq) { int ret; - char *newauthtok; + const char *password; char *salt; char *new_hash; struct pam_data *pd;
pd = lreq->preq->pd;
- newauthtok = talloc_strndup(lreq, (char *) pd->newauthtok, - pd->newauthtok_size); - NULL_CHECK_OR_JUMP(newauthtok, ("talloc_strndup failed.\n"), lreq->error, - ENOMEM, done); - memset(pd->newauthtok, 0, pd->newauthtok_size); - - if (strlen(newauthtok) == 0) { + ret = sss_authtok_get_password(&pd->newauthtok, &password, NULL); + if (ret) { /* TODO: should we allow null passwords via a config option ? */ - DEBUG(1, ("Empty passwords are not allowed!\n")); + if (ret == ENOENT) { + DEBUG(1, ("Empty passwords are not allowed!\n")); + } lreq->error = EINVAL; goto done; } @@ -179,11 +176,10 @@ static void do_pam_chauthtok(struct LOCAL_request *lreq) lreq->error, ret, done); DEBUG(4, ("Using salt [%s]\n", salt));
- ret = s3crypt_sha512(lreq, newauthtok, salt, &new_hash); + ret = s3crypt_sha512(lreq, password, salt, &new_hash); NEQ_CHECK_OR_JUMP(ret, EOK, ("Hash generation failed.\n"), lreq->error, ret, done); DEBUG(4, ("New hash [%s]\n", new_hash)); - memset(newauthtok, 0, pd->newauthtok_size);
lreq->mod_attrs = sysdb_new_attrs(lreq); NULL_CHECK_OR_JUMP(lreq->mod_attrs, ("sysdb_new_attrs failed.\n"), @@ -204,7 +200,7 @@ static void do_pam_chauthtok(struct LOCAL_request *lreq) lreq->error, ret, done);
done: - return; + sss_authtok_set_empty(&pd->newauthtok); }
int LOCAL_pam_handler(struct pam_auth_req *preq) @@ -223,9 +219,9 @@ int LOCAL_pam_handler(struct pam_auth_req *preq) NULL}; struct ldb_result *res; const char *username = NULL; - const char *password = NULL; + const char *pwdhash = NULL; char *new_hash = NULL; - char *authtok = NULL; + const char *password; struct pam_data *pd = preq->pd; int ret;
@@ -287,25 +283,22 @@ int LOCAL_pam_handler(struct pam_auth_req *preq) DEBUG(4, ("allowing root to reset a password.\n")); break; } - authtok = talloc_strndup(lreq, (char *) pd->authtok, - pd->authtok_size); - NULL_CHECK_OR_JUMP(authtok, ("talloc_strndup failed.\n"), - lreq->error, ENOMEM, done); - memset(pd->authtok, 0, pd->authtok_size); + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + NEQ_CHECK_OR_JUMP(ret, EOK, ("Failed to get password.\n"), + lreq->error, ret, done);
- password = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_PWD, NULL); - NULL_CHECK_OR_JUMP(password, ("No password stored.\n"), + pwdhash = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_PWD, NULL); + NULL_CHECK_OR_JUMP(pwdhash, ("No password stored.\n"), lreq->error, LDB_ERR_NO_SUCH_ATTRIBUTE, done); - DEBUG(4, ("user: [%s], password hash: [%s]\n", username, password)); + DEBUG(4, ("user: [%s], password hash: [%s]\n", username, pwdhash));
- ret = s3crypt_sha512(lreq, authtok, password, &new_hash); - memset(authtok, 0, pd->authtok_size); + ret = s3crypt_sha512(lreq, password, pwdhash, &new_hash); NEQ_CHECK_OR_JUMP(ret, EOK, ("nss_sha512_crypt failed.\n"), lreq->error, ret, done);
DEBUG(4, ("user: [%s], new hash: [%s]\n", username, new_hash));
- if (strcmp(new_hash, password) != 0) { + if (strcmp(new_hash, pwdhash) != 0) { DEBUG(1, ("Passwords do not match.\n")); do_failed_login(lreq); goto done; @@ -338,13 +331,8 @@ int LOCAL_pam_handler(struct pam_auth_req *preq) }
done: - if (pd->authtok != NULL) - memset(pd->authtok, 0, pd->authtok_size); - if (authtok != NULL) - memset(authtok, 0, pd->authtok_size); - if (pd->newauthtok != NULL) - memset(pd->newauthtok, 0, pd->newauthtok_size); - + sss_authtok_set_empty(&pd->newauthtok); + sss_authtok_set_empty(&pd->authtok); prepare_reply(lreq); return EOK; } diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index ed7438f8d1509568bcd12bbbe7ab73984780bcdd..813894d39767248f74addac8596890ba7213a352 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -49,21 +49,38 @@ enum pam_verbosity {
static void pam_reply(struct pam_auth_req *preq);
-static int extract_authtok(uint32_t *type, uint32_t *size, uint8_t **tok, - size_t data_size, uint8_t *body, size_t blen, - size_t *c) { +static int extract_authtok_v2(TALLOC_CTX *mem_ctx, struct sss_auth_token *tok, + size_t data_size, uint8_t *body, size_t blen, + size_t *c) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + uint8_t *auth_token_data; + int ret = EOK;
if (data_size < sizeof(uint32_t) || *c+data_size > blen || SIZE_T_OVERFLOW(*c, data_size)) return EINVAL; - *size = data_size - sizeof(uint32_t);
- SAFEALIGN_COPY_UINT32_CHECK(type, &body[*c], blen, c); + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, &body[*c], blen, c); + auth_token_length = data_size - sizeof(uint32_t); + auth_token_data = body+(*c);
- *tok = body+(*c); + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_set_password(mem_ctx, tok, + (const char *)auth_token_data, + auth_token_length); + break; + default: + return EINVAL; + }
- *c += (*size); + *c += auth_token_length;
- return EOK; + return ret; }
static int extract_string(char **var, size_t size, uint8_t *body, size_t blen, @@ -185,14 +202,13 @@ static int pam_parse_in_data_v2(struct sss_domain_info *domains, if (ret != EOK) return ret; break; case SSS_PAM_ITEM_AUTHTOK: - ret = extract_authtok(&pd->authtok_type, &pd->authtok_size, - &pd->authtok, size, body, blen, &c); + ret = extract_authtok_v2(pd, &pd->authtok, + size, body, blen, &c); if (ret != EOK) return ret; break; case SSS_PAM_ITEM_NEWAUTHTOK: - ret = extract_authtok(&pd->newauthtok_type, - &pd->newauthtok_size, - &pd->newauthtok, size, body, blen, &c); + ret = extract_authtok_v2(pd, &pd->newauthtok, + size, body, blen, &c); if (ret != EOK) return ret; break; default: @@ -232,14 +248,44 @@ static int pam_parse_in_data_v3(struct sss_domain_info *domains, return EOK; }
+static int extract_authtok_v1(TALLOC_CTX *mem_ctx, struct sss_auth_token *tok, + uint8_t *body, size_t blen, size_t *c) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + uint8_t *auth_token_data; + int ret = EOK; + + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, &body[*c], blen, c); + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_length, &body[*c], blen, c); + auth_token_data = body+(*c); + + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_set_password(mem_ctx, tok, + (const char *)auth_token_data, + auth_token_length); + break; + default: + return EINVAL; + } + + *c += auth_token_length; + + return ret; +} + static int pam_parse_in_data(struct sss_domain_info *domains, const char *default_domain, struct pam_data *pd, uint8_t *body, size_t blen) { - int start; - int end; - int last; + size_t start; + size_t end; + size_t last; int ret;
last = blen - 1; @@ -269,45 +315,15 @@ static int pam_parse_in_data(struct sss_domain_info *domains, if (body[end++] != '\0') return EINVAL; pd->rhost = (char *) &body[start];
- start = end; - pd->authtok_type = (int) body[start]; - - start += sizeof(uint32_t); - pd->authtok_size = (int) body[start]; - if (pd->authtok_size >= blen) return EINVAL; - - start += sizeof(uint32_t); - end = start + pd->authtok_size; - if (pd->authtok_size == 0) { - pd->authtok = NULL; - } else { - if (end <= blen) { - pd->authtok = (uint8_t *) &body[start]; - } else { - DEBUG(1, ("Invalid authtok size: %d\n", pd->authtok_size)); - return EINVAL; - } + ret = extract_authtok_v1(pd, &pd->authtok, body, blen, &end); + if (ret) { + DEBUG(1, ("Invalid auth token\n")); + return ret; } - - start = end; - pd->newauthtok_type = (int) body[start]; - - start += sizeof(uint32_t); - pd->newauthtok_size = (int) body[start]; - if (pd->newauthtok_size >= blen) return EINVAL; - - start += sizeof(uint32_t); - end = start + pd->newauthtok_size; - - if (pd->newauthtok_size == 0) { - pd->newauthtok = NULL; - } else { - if (end <= blen) { - pd->newauthtok = (uint8_t *) &body[start]; - } else { - DEBUG(1, ("Invalid newauthtok size: %d\n", pd->newauthtok_size)); - return EINVAL; - } + ret = extract_authtok_v1(pd, &pd->newauthtok, body, blen, &end); + if (ret) { + DEBUG(1, ("Invalid new auth token\n")); + return ret; }
DEBUG_PAM_DATA(4, pd); @@ -763,9 +779,9 @@ static void pam_reply(struct pam_auth_req *preq) goto done; }
- password = talloc_strndup(preq, pd->authtok, pd->authtok_size); - if (!password) { - DEBUG(0, ("Fatal: Out of memory copying password\n")); + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + if (ret) { + DEBUG(0, ("Failed to get password.\n")); goto done; }
@@ -775,10 +791,6 @@ static void pam_reply(struct pam_auth_req *preq) &exp_date, &delay_until);
pam_handle_cached_login(preq, ret, exp_date, delay_until); - if (password) { - for (i = 0; password[i]; i++) password[i] = 0; - talloc_zfree(password); - } return; } break; diff --git a/src/tests/krb5_child-test.c b/src/tests/krb5_child-test.c index 34d025b77b27a27e6131c1895c6c02644f921e5d..a72a3519985292456db6b9bbf9bccdcf678068a6 100644 --- a/src/tests/krb5_child-test.c +++ b/src/tests/krb5_child-test.c @@ -167,6 +167,9 @@ create_dummy_pam_data(TALLOC_CTX *mem_ctx, const char *user, const char *password) { struct pam_data *pd; + const char *authtok; + size_t authtok_len; + errno_t ret;
pd = talloc_zero(mem_ctx, struct pam_data); if (!pd) goto fail; @@ -175,12 +178,12 @@ create_dummy_pam_data(TALLOC_CTX *mem_ctx, const char *user, pd->user = talloc_strdup(pd, user); if (!pd->user) goto fail;
- pd->authtok = discard_const(talloc_strdup(pd, password)); - if (!pd->authtok) goto fail; - pd->authtok_size = strlen(password); - pd->authtok_type = SSS_AUTHTOK_TYPE_PASSWORD; + ret = sss_authtok_set_password(pd, &pd->authtok, password, 0); + if (ret) goto fail; + + (void)sss_authtok_get_password(&pd->authtok, &authtok, &authtok_len); DEBUG(SSSDBG_FUNC_DATA, ("Authtok [%s] len [%d]\n", - pd->authtok, pd->authtok_size)); + authtok, (int)authtok_len));
return pd;
On 12/02/2012 05:59 AM, Simo Sorce wrote:
These functions allow handling of auth tokens in a completely opaque way, with clear semantics and accessor fucntions that guarantee consistency, proper access to data and error conditions.
/home/pbrezina/workspace/sssd/.git/rebase-apply/patch:229: new blank line at EOF. + warning: 1 line adds whitespace errors.
Can we move enum sss_authtok_type to authtok.h?
+size_t sss_authtok_get_size(struct sss_auth_token *tok) +{
- switch (tok->type) {
- case SSS_AUTHTOK_TYPE_PASSWORD:
- case SSS_AUTHTOK_TYPE_CCFILE:
return tok->length;
- default:
return 0;
- }
+}
Return 0 for SSS_AUTHTOK_TYPE_CCFILE and print error otherwise? Also not using default branch for enum would be nice, because we'll get compiler error if we add new enum value and not handle it in switch.
+uint8_t *sss_authtok_get_data(struct sss_auth_token *tok) +{
- return (void *)tok->data;
+}
Why are you typecasting to void* when you are returning uint8_t*? And tok->data is already uint8_t*.
+static errno_t sss_authtok_set_string(TALLOC_CTX *mem_ctx,
struct sss_auth_token *tok,
enum sss_authtok_type type,
const char *context_name,
const char *str, size_t len)
+{
- size_t size;
- if (len == 0) {
len = strlen(str);
- } else {
while (len > 0 && str[len - 1] == '\0') len--;
- }
- if (len == 0) {
You should check len <= 0, because if negative len was passed in parameter list, it will get here unchanged.
/* we do not allow zero length ttyped tokens */
^ typo
return EINVAL;
- }
- size = len + 1;
- tok->data = talloc_named(mem_ctx, size, context_name);
- if (!tok->data) {
return ENOMEM;
- }
- memcpy(tok->data, str, len);
- tok->data[len] = '\0';
- tok->type = type;
- tok->length = size;
- return EOK;
+}
diff --git a/src/util/authtok.h b/src/util/authtok.h new file mode 100644 index 0000000000000000000000000000000000000000..c750711ea373506118aab75807dc706c217f6842 --- /dev/null +++ b/src/util/authtok.h @@ -0,0 +1,180 @@ +/*
- SSSD - auth utils
- Copyright (C) Simo Sorce simo@redhat.com 2012
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see http://www.gnu.org/licenses/.
+*/
+#ifndef __AUTHTOK_H__ +#define __AUTHTOK_H__
+#include "util/util.h" +#include "sss_client/sss_cli.h"
+/* Auth token structure,
- please never use directly.
- Use ss_authtok_* accesor functions instead
^typo
On Mon, 2012-12-03 at 15:34 +0100, Pavel Březina wrote:
On 12/02/2012 05:59 AM, Simo Sorce wrote:
These functions allow handling of auth tokens in a completely opaque way, with clear semantics and accessor fucntions that guarantee consistency, proper access to data and error conditions.
/home/pbrezina/workspace/sssd/.git/rebase-apply/patch:229: new blank line at EOF.
warning: 1 line adds whitespace errors.
Can we move enum sss_authtok_type to authtok.h?
Yes, I thought I did it, I had the same intention, will check if there is a reason why I did not, otherwise I'll move.
+size_t sss_authtok_get_size(struct sss_auth_token *tok) +{
- switch (tok->type) {
- case SSS_AUTHTOK_TYPE_PASSWORD:
- case SSS_AUTHTOK_TYPE_CCFILE:
return tok->length;
- default:
return 0;
- }
+}
Return 0 for SSS_AUTHTOK_TYPE_CCFILE and print error otherwise? Also not using default branch for enum would be nice, because we'll get compiler error if we add new enum value and not handle it in switch.
Oh, yes, I actually liked they were enum's exactly because then I could avoid 'default' ... thanks for catching this.
+uint8_t *sss_authtok_get_data(struct sss_auth_token *tok) +{
- return (void *)tok->data;
+}
Why are you typecasting to void* when you are returning uint8_t*? And tok->data is already uint8_t*.
bug, initially the interface was returning void *, then I change it, thanks for catching.
+static errno_t sss_authtok_set_string(TALLOC_CTX *mem_ctx,
struct sss_auth_token *tok,
enum sss_authtok_type type,
const char *context_name,
const char *str, size_t len)
+{
- size_t size;
- if (len == 0) {
len = strlen(str);
- } else {
while (len > 0 && str[len - 1] == '\0') len--;
- }
- if (len == 0) {
You should check len <= 0, because if negative len was passed in parameter list, it will get here unchanged.
size_t is unsigned, it can't represent negative numbers :-)
/* we do not allow zero length ttyped tokens */
^ typo
will fix
+/* Auth token structure,
- please never use directly.
- Use ss_authtok_* accesor functions instead
^typo
as well.
Thanks, Simo.
On 12/02/2012 05:59 AM, Simo Sorce wrote:
This is useful for wiping passwords, as it prevents the compiler from optimizing out a memset to zero before a free()
src/util/util.c | 9 +++++++++ src/util/util.h | 9 +++++++++ 2 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/src/util/util.c b/src/util/util.c index ab980775a1e4c87b16d32220bccda6cb644e0756..f268fbcd564cd93a2e63097c595cf19b65eb6800 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -700,3 +700,12 @@ bool string_in_list(const char *string, char **list, bool case_sensitive)
return false;
}
+void safezero(void *data, size_t size) +{
- volatile uint8_t *p = data;
- while (size--) {
*p++ = 0;
- }
+} diff --git a/src/util/util.h b/src/util/util.h index c15ca668392105447d073c40666953a0145d375a..1c5f3fc52292e251bf7b8ad4d5b03a9d8a0a3243 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -540,6 +540,15 @@ errno_t add_string_to_list(TALLOC_CTX *mem_ctx, const char *string,
bool string_in_list(const char *string, char **list, bool case_sensitive);
+/**
- @brief Safely zero a segment of memory,
prevents the compiler from optimizing out
- @param data The address of buffer to wipe
- @param s Size of the buffer
- */
+void safezero(void *data, size_t size);
- /* from sss_tc_utf8.c */ char * sss_tc_utf8_str_tolower(TALLOC_CTX *mem_ctx, const char *s);
Why didn't you use memset?
On Mon, 2012-12-03 at 15:34 +0100, Pavel Březina wrote:
On 12/02/2012 05:59 AM, Simo Sorce wrote:
This is useful for wiping passwords, as it prevents the compiler from optimizing out a memset to zero before a free()
src/util/util.c | 9 +++++++++ src/util/util.h | 9 +++++++++ 2 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/src/util/util.c b/src/util/util.c index ab980775a1e4c87b16d32220bccda6cb644e0756..f268fbcd564cd93a2e63097c595cf19b65eb6800 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -700,3 +700,12 @@ bool string_in_list(const char *string, char **list, bool case_sensitive)
return false;
}
+void safezero(void *data, size_t size) +{
- volatile uint8_t *p = data;
- while (size--) {
*p++ = 0;
- }
+} diff --git a/src/util/util.h b/src/util/util.h index c15ca668392105447d073c40666953a0145d375a..1c5f3fc52292e251bf7b8ad4d5b03a9d8a0a3243 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -540,6 +540,15 @@ errno_t add_string_to_list(TALLOC_CTX *mem_ctx, const char *string,
bool string_in_list(const char *string, char **list, bool case_sensitive);
+/**
- @brief Safely zero a segment of memory,
prevents the compiler from optimizing out
- @param data The address of buffer to wipe
- @param s Size of the buffer
- */
+void safezero(void *data, size_t size);
- /* from sss_tc_utf8.c */ char * sss_tc_utf8_str_tolower(TALLOC_CTX *mem_ctx, const char *s);
Why didn't you use memset?
Memset is optimized away by most compilers when it is followed by a free(), because it is a useless operation 'normally'. However we use this function to make *sure* we overwrite this memory as we do not want to leave passwords in memory for longer than needed. Should a core be dumped we will leave as little as possible in the core file. In order to make sure compilers do not optimized it out we need this special function that uses volatile so the compiler is forbidden from optimizing it out.
Simo.
On 12/02/2012 05:59 AM, Simo Sorce wrote:
Rebased again as requested by Pavel
Simo Sorce (4): Code can only check for cached passwords Add function to safely wipe memory. Add authtok utility functions. Change pam data auth tokens.
Makefile.am | 4 + src/db/sysdb.h | 3 +- src/db/sysdb_ops.c | 13 +-- src/providers/data_provider.h | 9 +- src/providers/dp_auth_util.c | 76 +++++--- src/providers/dp_pam_data_util.c | 113 ++++++------ src/providers/ipa/ipa_auth.c | 6 +- src/providers/krb5/krb5_auth.c | 52 +++--- src/providers/krb5/krb5_child.c | 148 ++++++++------- src/providers/krb5/krb5_child_handler.c | 59 +++++- .../krb5/krb5_delayed_online_authentication.c | 50 ++++-- src/providers/krb5/krb5_renew_tgt.c | 18 +-- src/providers/ldap/ldap_auth.c | 90 ++++------ src/providers/ldap/sdap_async.c | 4 +- src/providers/ldap/sdap_async.h | 7 +- src/providers/ldap/sdap_async_connection.c | 88 +++++---- src/providers/proxy/proxy.h | 7 +- src/providers/proxy/proxy_auth.c | 14 +- src/providers/proxy/proxy_child.c | 51 +++-- src/responder/pam/pam_LOCAL_domain.c | 52 ++---- src/responder/pam/pamsrv_cmd.c | 159 +++++++++------- src/tests/krb5_child-test.c | 13 +- src/tests/sysdb-tests.c | 6 +- src/util/authtok.c | 195 ++++++++++++++++++++ src/util/authtok.h | 180 ++++++++++++++++++ src/util/util.c | 9 + src/util/util.h | 9 + 27 files changed, 950 insertions(+), 485 deletions(-) create mode 100644 src/util/authtok.c create mode 100644 src/util/authtok.h
sssd-devel mailing list sssd-devel@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/sssd-devel
Hi, thanks. I'm seeing following errors:
src/providers/krb5/krb5_auth.c: In function 'krb5_auth_store_creds': src/providers/krb5/krb5_auth.c:394:13: warning: passing argument 2 of 'sss_authtok_get_password' from incompatible pointer type [enabled by default] In file included from ./src/providers/data_provider.h:44:0, from ./src/providers/dp_backend.h:25, from ./src/providers/krb5/krb5_auth.h:32, from src/providers/krb5/krb5_auth.c:40: ./src/util/authtok.h:76:9: note: expected 'const char **' but argument is of type 'char **' src/providers/krb5/krb5_auth.c:397:13: warning: passing argument 2 of 'sss_authtok_get_password' from incompatible pointer type [enabled by default] In file included from ./src/providers/data_provider.h:44:0, from ./src/providers/dp_backend.h:25, from ./src/providers/krb5/krb5_auth.h:32, from src/providers/krb5/krb5_auth.c:40: ./src/util/authtok.h:76:9: note: expected 'const char **' but argument is of type 'char **' src/providers/krb5/krb5_auth.c:414:9: error: 'tmp_ctx' undeclared (first use in this function) src/providers/krb5/krb5_auth.c:414:9: note: each undeclared identifier is reported only once for each function it appears in
I'll send per patch review separately.
Sorry for the previous non-building rebase, my fault, it was just a rebase silently working but generating errors as the underlying code was slightly changed.
Additional fixes for patch 3 as per PAvel comment. Couldn;t move the enum definition because it is use by pam_sss.c too and that's in the client which can;t include authtok.c
Builds, but haven;t re-tested due to time constraints.
Simo.
Simo Sorce (4): Code can only check for cached passwords Add function to safely wipe memory. Add authtok utility functions. Change pam data auth tokens.
Makefile.am | 4 + src/db/sysdb.h | 3 +- src/db/sysdb_ops.c | 13 +-- src/providers/data_provider.h | 9 +- src/providers/dp_auth_util.c | 76 +++++--- src/providers/dp_pam_data_util.c | 113 ++++++------ src/providers/ipa/ipa_auth.c | 6 +- src/providers/krb5/krb5_auth.c | 55 +++--- src/providers/krb5/krb5_child.c | 148 ++++++++------- src/providers/krb5/krb5_child_handler.c | 59 +++++- .../krb5/krb5_delayed_online_authentication.c | 50 ++++-- src/providers/krb5/krb5_renew_tgt.c | 18 +-- src/providers/ldap/ldap_auth.c | 90 ++++------ src/providers/ldap/sdap_async.c | 4 +- src/providers/ldap/sdap_async.h | 7 +- src/providers/ldap/sdap_async_connection.c | 88 +++++---- src/providers/proxy/proxy.h | 7 +- src/providers/proxy/proxy_auth.c | 14 +- src/providers/proxy/proxy_child.c | 51 +++-- src/responder/pam/pam_LOCAL_domain.c | 52 ++---- src/responder/pam/pamsrv_cmd.c | 159 +++++++++------- src/tests/krb5_child-test.c | 13 +- src/tests/sysdb-tests.c | 6 +- src/util/authtok.c | 194 ++++++++++++++++++++ src/util/authtok.h | 180 ++++++++++++++++++ src/util/util.c | 9 + src/util/util.h | 9 + 27 files changed, 950 insertions(+), 487 deletions(-) create mode 100644 src/util/authtok.c create mode 100644 src/util/authtok.h
Make it clear to the API users that we can not take arbitrary auth tokens. We can only take a password for now so simplify and clarify the interface. --- src/db/sysdb.h | 3 +-- src/db/sysdb_ops.c | 12 +----------- src/providers/krb5/krb5_auth.c | 21 +++++++++++++++++---- src/responder/pam/pamsrv_cmd.c | 39 ++++++++++++++++++++++++--------------- src/tests/sysdb-tests.c | 6 ++---- 5 files changed, 45 insertions(+), 36 deletions(-)
diff --git a/src/db/sysdb.h b/src/db/sysdb.h index ed00c165952aa80102b88c9e857355f2ef27d570..892414797304a1ba86a041279aea9bcafe1fd3cd 100644 --- a/src/db/sysdb.h +++ b/src/db/sysdb.h @@ -778,8 +778,7 @@ errno_t check_failed_login_attempts(struct confdb_ctx *cdb, time_t *delayed_until); int sysdb_cache_auth(struct sysdb_ctx *sysdb, const char *name, - const uint8_t *authtok, - size_t authtok_size, + const char *password, struct confdb_ctx *cdb, bool just_check, time_t *_expire_date, diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c index 80a323b12901b40f6df0c4cd0f0b23b4cf2cf2b2..e213023e3f1f1342984b7b2464a23a4544df9010 100644 --- a/src/db/sysdb_ops.c +++ b/src/db/sysdb_ops.c @@ -2674,8 +2674,7 @@ done:
int sysdb_cache_auth(struct sysdb_ctx *sysdb, const char *name, - const uint8_t *authtok, - size_t authtok_size, + const char *password, struct confdb_ctx *cdb, bool just_check, time_t *_expire_date, @@ -2690,7 +2689,6 @@ int sysdb_cache_auth(struct sysdb_ctx *sysdb, struct ldb_message *ldb_msg; const char *userhash; char *comphash; - char *password = NULL; uint64_t lastLogin = 0; int cred_expiration; uint32_t failed_login_attempts = 0; @@ -2776,13 +2774,6 @@ int sysdb_cache_auth(struct sysdb_ctx *sysdb,
/* TODO: verify user account (disabled, expired ...) */
- password = talloc_strndup(tmp_ctx, (const char *)authtok, authtok_size); - if (password == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - ret = ENOMEM; - goto done; - } - userhash = ldb_msg_find_attr_as_string(ldb_msg, SYSDB_CACHEDPWD, NULL); if (userhash == NULL || *userhash == '\0') { DEBUG(4, ("Cached credentials not available.\n")); @@ -2866,7 +2857,6 @@ done: if (_delayed_until != NULL) { *_delayed_until = delayed_until; } - if (password) for (i = 0; password[i]; i++) password[i] = 0; if (ret) { ldb_transaction_cancel(sysdb->ldb); } else { diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c index 7104b3127e04891fed7370a6241c60865372632b..5ef6cfc28625c55d850b73dc8cc621f33da1bdce 100644 --- a/src/providers/krb5/krb5_auth.c +++ b/src/providers/krb5/krb5_auth.c @@ -278,16 +278,23 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, struct pam_data *pd, uid_t uid, int *pam_status, int *dp_err) { + char *password = NULL; errno_t ret;
- ret = sysdb_cache_auth(sysdb, pd->user, pd->authtok, - pd->authtok_size, cdb, true, NULL, - NULL); + password = talloc_strndup(state, pd->authtok, pd->authtok_size); + if (!password) { + DEBUG(0, ("Out of memory copying password\n")); + *pam_status = PAM_SYSTEM_ERR; + *dp_err = DP_ERR_OK; + return; + } + + ret = sysdb_cache_auth(sysdb, pd->user, password, cdb, true, NULL, NULL); if (ret != EOK) { DEBUG(1, ("Offline authentication failed\n")); *pam_status = cached_login_pam_status(ret); *dp_err = DP_ERR_OK; - return; + goto done; }
ret = add_user_to_delayed_online_authentication(krb5_ctx, pd, uid); @@ -297,6 +304,12 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, } *pam_status = PAM_AUTHINFO_UNAVAIL; *dp_err = DP_ERR_OFFLINE; + +done: + if (password) { + for (i = 0; password[i]; i++) password[i] = 0; + talloc_zfree(password); + } }
static errno_t krb5_auth_prepare_ccache_file(struct krb5child_req *kr, diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index 4269642206cc0295c0046de4e59a3ad8f1044d1a..ed7438f8d1509568bcd12bbbe7ab73984780bcdd 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -733,7 +733,6 @@ static void pam_reply(struct pam_auth_req *preq) struct timeval tv; struct tevent_timer *te; struct pam_data *pd; - struct sysdb_ctx *sysdb; struct pam_ctx *pctx; uint32_t user_info_type; time_t exp_date = -1; @@ -753,24 +752,34 @@ static void pam_reply(struct pam_auth_req *preq) if ((preq->domain != NULL) && (preq->domain->cache_credentials == true) && (pd->offline_auth == false)) { + const char *password = NULL;
- /* do auth with offline credentials */ - pd->offline_auth = true; + /* do auth with offline credentials */ + pd->offline_auth = true;
- sysdb = preq->domain->sysdb; - if (sysdb == NULL) { - DEBUG(0, ("Fatal: Sysdb CTX not found for " - "domain [%s]!\n", preq->domain->name)); - goto done; - } + if (preq->domain->sysdb == NULL) { + DEBUG(0, ("Fatal: Sysdb CTX not found for domain" + " [%s]!\n", preq->domain->name)); + goto done; + }
- ret = sysdb_cache_auth(sysdb, pd->user, - pd->authtok, pd->authtok_size, - pctx->rctx->cdb, false, - &exp_date, &delay_until); + password = talloc_strndup(preq, pd->authtok, pd->authtok_size); + if (!password) { + DEBUG(0, ("Fatal: Out of memory copying password\n")); + goto done; + }
- pam_handle_cached_login(preq, ret, exp_date, delay_until); - return; + ret = sysdb_cache_auth(preq->domain->sysdb, + pd->user, password, + pctx->rctx->cdb, false, + &exp_date, &delay_until); + + pam_handle_cached_login(preq, ret, exp_date, delay_until); + if (password) { + for (i = 0; password[i]; i++) password[i] = 0; + talloc_zfree(password); + } + return; } break; case SSS_PAM_CHAUTHTOK_PRELIM: diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c index 74b75233d7a5cf027ffdf581cbc9942ba2cc2b95..06cda816d79986d099d24457c40af7264b5a1a44 100644 --- a/src/tests/sysdb-tests.c +++ b/src/tests/sysdb-tests.c @@ -1576,8 +1576,7 @@ static void cached_authentication_without_expiration(const char *username, return; }
- ret = sysdb_cache_auth(test_ctx->sysdb, data->username, - (const uint8_t *)password, strlen(password), + ret = sysdb_cache_auth(test_ctx->sysdb, data->username, password, test_ctx->confdb, false, &expire_date, &delayed_until);
fail_unless(ret == expected_result, "sysdb_cache_auth request does not " @@ -1636,8 +1635,7 @@ static void cached_authentication_with_expiration(const char *username, data->attrs, SYSDB_MOD_REP); fail_unless(ret == EOK, "Could not modify user %s", data->username);
- ret = sysdb_cache_auth(test_ctx->sysdb, data->username, - (const uint8_t *) password, strlen(password), + ret = sysdb_cache_auth(test_ctx->sysdb, data->username, password, test_ctx->confdb, false, &expire_date, &delayed_until);
fail_unless(ret == expected_result,
This is useful for wiping passwords, as it prevents the compiler from optimizing out a memset to zero before a free() --- src/util/util.c | 9 +++++++++ src/util/util.h | 9 +++++++++ 2 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/src/util/util.c b/src/util/util.c index ab980775a1e4c87b16d32220bccda6cb644e0756..f268fbcd564cd93a2e63097c595cf19b65eb6800 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -700,3 +700,12 @@ bool string_in_list(const char *string, char **list, bool case_sensitive)
return false; } + +void safezero(void *data, size_t size) +{ + volatile uint8_t *p = data; + + while (size--) { + *p++ = 0; + } +} diff --git a/src/util/util.h b/src/util/util.h index c15ca668392105447d073c40666953a0145d375a..1c5f3fc52292e251bf7b8ad4d5b03a9d8a0a3243 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -540,6 +540,15 @@ errno_t add_string_to_list(TALLOC_CTX *mem_ctx, const char *string,
bool string_in_list(const char *string, char **list, bool case_sensitive);
+/** + * @brief Safely zero a segment of memory, + * prevents the compiler from optimizing out + * + * @param data The address of buffer to wipe + * @param s Size of the buffer + */ +void safezero(void *data, size_t size); + /* from sss_tc_utf8.c */ char * sss_tc_utf8_str_tolower(TALLOC_CTX *mem_ctx, const char *s);
These functions allow handling of auth tokens in a completely opaque way, with clear semantics and accessor fucntions that guarantee consistency, proper access to data and error conditions. --- Makefile.am | 2 + src/util/authtok.c | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/util/authtok.h | 180 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 376 insertions(+), 0 deletions(-) create mode 100644 src/util/authtok.c create mode 100644 src/util/authtok.h
diff --git a/Makefile.am b/Makefile.am index ce3f94f635f918438bf856c523e47c0f09fc328a..1e4442c4a4bdfafccf1db923d650da4d161ae480 100644 --- a/Makefile.am +++ b/Makefile.am @@ -369,6 +369,7 @@ dist_noinst_HEADERS = \ src/util/mmap_cache.h \ src/util/atomic_io.h \ src/util/auth_utils.h \ + src/util/authtok.h \ src/monitor/monitor.h \ src/monitor/monitor_interfaces.h \ src/responder/common/responder.h \ @@ -507,6 +508,7 @@ libsss_util_la_SOURCES = \ src/util/sss_tc_utf8.c \ src/util/murmurhash3.c \ src/util/atomic_io.c \ + src/util/authtok.c \ src/util/sss_selinux.c \ src/util/domain_info_utils.c \ src/util/util_lock.c diff --git a/src/util/authtok.c b/src/util/authtok.c new file mode 100644 index 0000000000000000000000000000000000000000..65047a3574a954da5cd5ec58943fb6f59d10c156 --- /dev/null +++ b/src/util/authtok.c @@ -0,0 +1,194 @@ +/* + SSSD - auth utils + + Copyright (C) Simo Sorce simo@redhat.com 2012 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses/. +*/ + +#include "authtok.h" + +enum sss_authtok_type sss_authtok_get_type(struct sss_auth_token *tok) +{ + return tok->type; +} + +size_t sss_authtok_get_size(struct sss_auth_token *tok) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_PASSWORD: + case SSS_AUTHTOK_TYPE_CCFILE: + return tok->length; + case SSS_AUTHTOK_TYPE_EMPTY: + return 0; + } +} + +uint8_t *sss_authtok_get_data(struct sss_auth_token *tok) +{ + return tok->data; +} + +errno_t sss_authtok_get_password(struct sss_auth_token *tok, + const char **pwd, size_t *len) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_EMPTY: + return ENOENT; + case SSS_AUTHTOK_TYPE_PASSWORD: + *pwd = (const char *)tok->data; + if (len) { + *len = tok->length - 1; + } + return EOK; + case SSS_AUTHTOK_TYPE_CCFILE: + return EACCES; + } +} + +errno_t sss_authtok_get_ccfile(struct sss_auth_token *tok, + const char **ccfile, size_t *len) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_EMPTY: + return ENOENT; + case SSS_AUTHTOK_TYPE_CCFILE: + *ccfile = (const char *)tok->data; + if (len) { + *len = tok->length - 1; + } + return EOK; + case SSS_AUTHTOK_TYPE_PASSWORD: + return EACCES; + } +} + +static errno_t sss_authtok_set_string(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + enum sss_authtok_type type, + const char *context_name, + const char *str, size_t len) +{ + size_t size; + + if (len == 0) { + len = strlen(str); + } else { + while (len > 0 && str[len - 1] == '\0') len--; + } + + if (len == 0) { + /* we do not allow zero length typed tokens */ + return EINVAL; + } + + size = len + 1; + + tok->data = talloc_named(mem_ctx, size, context_name); + if (!tok->data) { + return ENOMEM; + } + memcpy(tok->data, str, len); + tok->data[len] = '\0'; + tok->type = type; + tok->length = size; + + return EOK; + +} + +void sss_authtok_set_empty(struct sss_auth_token *tok) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_EMPTY: + return; + case SSS_AUTHTOK_TYPE_PASSWORD: + safezero(tok->data, tok->length); + break; + case SSS_AUTHTOK_TYPE_CCFILE: + break; + } + + tok->type = SSS_AUTHTOK_TYPE_EMPTY; + talloc_zfree(tok->data); + tok->length = 0; +} + +errno_t sss_authtok_set_password(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *password, size_t len) +{ + sss_authtok_set_empty(tok); + + return sss_authtok_set_string(mem_ctx, tok, + SSS_AUTHTOK_TYPE_PASSWORD, + "password", password, len); +} + +errno_t sss_authtok_set_ccfile(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *ccfile, size_t len) +{ + sss_authtok_set_empty(tok); + + return sss_authtok_set_string(mem_ctx, tok, + SSS_AUTHTOK_TYPE_CCFILE, + "ccfile", ccfile, len); +} + +errno_t sss_authtok_set(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + enum sss_authtok_type type, + uint8_t *data, size_t len) +{ + switch (type) { + case SSS_AUTHTOK_TYPE_PASSWORD: + return sss_authtok_set_password(mem_ctx, tok, (const char *)data, len); + case SSS_AUTHTOK_TYPE_CCFILE: + return sss_authtok_set_ccfile(mem_ctx, tok, (const char *)data, len); + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + return EOK; + } +} + +errno_t sss_authtok_copy(TALLOC_CTX *mem_ctx, + struct sss_auth_token *src, + struct sss_auth_token *dst) +{ + sss_authtok_set_empty(dst); + + if (src->type == SSS_AUTHTOK_TYPE_EMPTY) { + return EOK; + } + + dst->data = talloc_memdup(mem_ctx, src->data, src->length); + if (!dst->data) { + return ENOMEM; + } + dst->length = src->length; + dst->type = src->type; + + return EOK; +} + +void sss_authtok_wipe_password(struct sss_auth_token *tok) +{ + if (tok->type != SSS_AUTHTOK_TYPE_PASSWORD) { + return; + } + + safezero(tok->data, tok->length); +} + diff --git a/src/util/authtok.h b/src/util/authtok.h new file mode 100644 index 0000000000000000000000000000000000000000..21cfe4a1c85489f7456651042bdf8041d7c55f58 --- /dev/null +++ b/src/util/authtok.h @@ -0,0 +1,180 @@ +/* + SSSD - auth utils + + Copyright (C) Simo Sorce simo@redhat.com 2012 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses/. +*/ + +#ifndef __AUTHTOK_H__ +#define __AUTHTOK_H__ + +#include "util/util.h" +#include "sss_client/sss_cli.h" + +/* Auth token structure, + * please never use directly. + * Use sss_authtok_* accesor functions instead + */ +struct sss_auth_token { + enum sss_authtok_type type; + uint8_t *data; + size_t length; +}; + +/** + * @brief Returns the token type + * + * @param tok A pointer to an sss_auth_token + * + * @return A sss_authtok_type (empty, password, ...) + */ +enum sss_authtok_type sss_authtok_get_type(struct sss_auth_token *tok); + +/** + * @brief Returns the token size + * + * @param tok A pointer to an sss_auth_token + * + * @return The current size of the token payload + */ +size_t sss_authtok_get_size(struct sss_auth_token *tok); + +/** + * @brief Get the data buffer + * + * @param tok A pointer to an sss_auth_token + * + * @return A pointer to the token payload + */ +uint8_t *sss_authtok_get_data(struct sss_auth_token *tok); + +/** + * @brief Returns a const string if the auth token is of type + SSS_AUTHTOK_TYPE_PASSWORD, otherwise it returns an error + * + * @param tok A pointer to an sss_auth_token + * @param pwd A pointer to a const char *, that will point to a null + * terminated string + * @param len The length of the password string + * + * @return EOK on success + * ENOENT if the token is empty + * EACCESS if the token is not a password token + */ +errno_t sss_authtok_get_password(struct sss_auth_token *tok, + const char **pwd, size_t *len); + +/** + * @brief Set a password into a an auth token, replacing any previous data + * + * @param mem_ctx A memory context use to allocate the internal data + * @param tok A pointer to a sss_auth_token structure to change + * @param password A string + * @param len The length of the string or, if 0 is passed, + * then strlen(password) will be used internally. + * + * @return EOK on success + * ENOMEM on error + */ +errno_t sss_authtok_set_password(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *password, size_t len); + +/** + * @brief Returns a const string if the auth token is of type + SSS_AUTHTOK_TYPE_CCFILE, otherwise it returns an error + * + * @param tok A pointer to an sss_auth_token + * @param ccfile A pointer to a const char *, that will point to a null + * terminated string + * @param len The length of the string + * + * @return EOK on success + * ENOENT if the token is empty + * EACCESS if the token is not a password token + */ +errno_t sss_authtok_get_ccfile(struct sss_auth_token *tok, + const char **ccfile, size_t *len); + +/** + * @brief Set a cc file name into a an auth token, replacing any previous data + * + * @param mem_ctx A memory context use to allocate the internal data + * @param tok A pointer to a sss_auth_token structure to change + * @param ccfile A null terminated string + * @param len The length of the string + * + * @return EOK on success + * ENOMEM on error + */ +errno_t sss_authtok_set_ccfile(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *ccfile, size_t len); + +/** + * @brief Resets an auth token to the empty status + * + * @param tok A pointer to a sss_auth_token structure to reset + * + * NOTE: This function uses safezero() on the payload if the type + * is SSS_AUTHTOK_TYPE_PASSWORD + */ +void sss_authtok_set_empty(struct sss_auth_token *tok); + +/** + * @brief Set an auth token by type, replacing any previous data + * + * @param mem_ctx A memory context use to allocate the internal data + * @param tok A pointer to a sss_auth_token structure to change + * @param type A valid authtok type + * @param ccfile A data pointer + * @param len The length of the data + * + * @return EOK on success + * ENOMEM or EINVAL on error + */ +errno_t sss_authtok_set(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + enum sss_authtok_type type, + uint8_t *data, size_t len); + +/** + * @brief Copy an auth token from source to destination + * + * @param mem_ctx The memory context to use for allocations on dst + * @param src The source auth token + * @param dst The destination auth token + * + * @return EOK on success + * ENOMEM on error + */ +errno_t sss_authtok_copy(TALLOC_CTX *mem_ctx, + struct sss_auth_token *src, + struct sss_auth_token *dst); + +/** + * @brief Uses safezero to wipe the password from memory if the + * authtoken contains a password, otherwise does nothing. + * + * @param tok A pointer to a sss_auth_token structure to change + * + * NOTE: This function should only be used in destructors or similar + * functions where freing the actual string is unsafe and where it can + * be guaranteed that the auth token will not be used anymore. + * Use sss_authtok_set_empty() in normal circumstances. + */ +void sss_authtok_wipe_password(struct sss_auth_token *tok); + +#endif /* __AUTHTOK_H__ */
Use the new authtok abstraction and interfaces throught the code. --- Makefile.am | 2 + src/db/sysdb_ops.c | 1 - src/providers/data_provider.h | 9 +- src/providers/dp_auth_util.c | 76 +++++++---- src/providers/dp_pam_data_util.c | 113 ++++++++------- src/providers/ipa/ipa_auth.c | 6 +- src/providers/krb5/krb5_auth.c | 58 +++----- src/providers/krb5/krb5_child.c | 148 ++++++++++---------- src/providers/krb5/krb5_child_handler.c | 59 +++++++-- .../krb5/krb5_delayed_online_authentication.c | 50 +++++--- src/providers/krb5/krb5_renew_tgt.c | 18 +-- src/providers/ldap/ldap_auth.c | 90 +++++------- src/providers/ldap/sdap_async.c | 4 +- src/providers/ldap/sdap_async.h | 7 +- src/providers/ldap/sdap_async_connection.c | 88 +++++++----- src/providers/proxy/proxy.h | 7 +- src/providers/proxy/proxy_auth.c | 14 +- src/providers/proxy/proxy_child.c | 51 ++++--- src/responder/pam/pam_LOCAL_domain.c | 52 +++----- src/responder/pam/pamsrv_cmd.c | 134 ++++++++++-------- src/tests/krb5_child-test.c | 13 +- 21 files changed, 530 insertions(+), 470 deletions(-)
diff --git a/Makefile.am b/Makefile.am index 1e4442c4a4bdfafccf1db923d650da4d161ae480..06f6280913e0419210852872663f0220455cc909 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1446,6 +1446,7 @@ krb5_child_SOURCES = \ src/util/user_info_msg.c \ src/util/sss_krb5.c \ src/util/atomic_io.c \ + src/util/authtok.c \ src/util/util.c \ src/util/signal.c \ src/sss_client/common.c @@ -1467,6 +1468,7 @@ ldap_child_SOURCES = \ src/providers/ldap/ldap_child.c \ src/util/sss_krb5.c \ src/util/atomic_io.c \ + src/util/authtok.c \ src/util/util.c \ src/util/signal.c ldap_child_CFLAGS = \ diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c index e213023e3f1f1342984b7b2464a23a4544df9010..c7a5372b99baa534d79e4fb65db7a420d11b5662 100644 --- a/src/db/sysdb_ops.c +++ b/src/db/sysdb_ops.c @@ -2697,7 +2697,6 @@ int sysdb_cache_auth(struct sysdb_ctx *sysdb, time_t expire_date = -1; time_t delayed_until = -1; int ret; - int i;
if (name == NULL || *name == '\0') { DEBUG(1, ("Missing user name.\n")); diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h index bb944509da9f1dc89216266cf62c57fb4127fd57..b370aa51dbe4015a26512a0f003defdb6851bf63 100644 --- a/src/providers/data_provider.h +++ b/src/providers/data_provider.h @@ -41,6 +41,7 @@ #include "sbus/sssd_dbus.h" #include "sbus/sbus_client.h" #include "sss_client/sss_cli.h" +#include "util/authtok.h"
#define DATA_PROVIDER_VERSION 0x0001 #define DATA_PROVIDER_PIPE "private/sbus-dp" @@ -162,18 +163,14 @@ struct response_data {
struct pam_data { int cmd; - uint32_t authtok_type; - uint32_t authtok_size; - uint32_t newauthtok_type; - uint32_t newauthtok_size; char *domain; char *user; char *service; char *tty; char *ruser; char *rhost; - uint8_t *authtok; - uint8_t *newauthtok; + struct sss_auth_token authtok; + struct sss_auth_token newauthtok; uint32_t cli_pid;
int pam_status; diff --git a/src/providers/dp_auth_util.c b/src/providers/dp_auth_util.c index 9a67564b78e558642f4116528d210251a0d9b5fd..54f0ee8ed6f1d537410a91f93e55316fc9b89886 100644 --- a/src/providers/dp_auth_util.c +++ b/src/providers/dp_auth_util.c @@ -24,30 +24,43 @@ bool dp_pack_pam_request(DBusMessage *msg, struct pam_data *pd) { dbus_bool_t db_ret; + const char *service; + const char *tty; + const char *ruser; + const char *rhost; + uint32_t authtok_type; + uint32_t authtok_length; + uint8_t *authtok_data; + uint32_t new_authtok_type; + uint32_t new_authtok_length; + uint8_t *new_authtok_data;
if (pd->user == NULL) return false; - if (pd->service == NULL) pd->service = talloc_strdup(pd, ""); - if (pd->tty == NULL) pd->tty = talloc_strdup(pd, ""); - if (pd->ruser == NULL) pd->ruser = talloc_strdup(pd, ""); - if (pd->rhost == NULL) pd->rhost = talloc_strdup(pd, ""); - + service = pd->service ? pd->service : ""; + tty = pd->tty ? pd->tty : ""; + ruser = pd->ruser ? pd->ruser : ""; + rhost = pd->rhost ? pd->rhost : ""; + authtok_type = (uint32_t)sss_authtok_get_type(&pd->authtok); + authtok_data = sss_authtok_get_data(&pd->authtok); + authtok_length = sss_authtok_get_size(&pd->authtok); + new_authtok_type = (uint32_t)sss_authtok_get_type(&pd->newauthtok); + new_authtok_data = sss_authtok_get_data(&pd->newauthtok); + new_authtok_length = sss_authtok_get_size(&pd->newauthtok);
db_ret = dbus_message_append_args(msg, DBUS_TYPE_INT32, &(pd->cmd), DBUS_TYPE_STRING, &(pd->user), DBUS_TYPE_STRING, &(pd->domain), - DBUS_TYPE_STRING, &(pd->service), - DBUS_TYPE_STRING, &(pd->tty), - DBUS_TYPE_STRING, &(pd->ruser), - DBUS_TYPE_STRING, &(pd->rhost), - DBUS_TYPE_UINT32, &(pd->authtok_type), + DBUS_TYPE_STRING, &service, + DBUS_TYPE_STRING, &tty, + DBUS_TYPE_STRING, &ruser, + DBUS_TYPE_STRING, &rhost, + DBUS_TYPE_UINT32, &authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd->authtok), - (pd->authtok_size), - DBUS_TYPE_UINT32, &(pd->newauthtok_type), + &authtok_data, authtok_length, + DBUS_TYPE_UINT32, &new_authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd->newauthtok), - pd->newauthtok_size, + &new_authtok_data, new_authtok_length, DBUS_TYPE_INT32, &(pd->priv), DBUS_TYPE_UINT32, &(pd->cli_pid), DBUS_TYPE_INVALID); @@ -61,6 +74,12 @@ bool dp_unpack_pam_request(DBusMessage *msg, TALLOC_CTX *mem_ctx, dbus_bool_t db_ret; int ret; struct pam_data pd; + uint32_t authtok_type; + uint32_t authtok_length; + uint8_t *authtok_data; + uint32_t new_authtok_type; + uint32_t new_authtok_length; + uint8_t *new_authtok_data;
memset(&pd, 0, sizeof(pd));
@@ -72,14 +91,12 @@ bool dp_unpack_pam_request(DBusMessage *msg, TALLOC_CTX *mem_ctx, DBUS_TYPE_STRING, &(pd.tty), DBUS_TYPE_STRING, &(pd.ruser), DBUS_TYPE_STRING, &(pd.rhost), - DBUS_TYPE_UINT32, &(pd.authtok_type), + DBUS_TYPE_UINT32, &authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd.authtok), - &(pd.authtok_size), - DBUS_TYPE_UINT32, &(pd.newauthtok_type), + &authtok_data, &authtok_length, + DBUS_TYPE_UINT32, &new_authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd.newauthtok), - &(pd.newauthtok_size), + &new_authtok_data, &new_authtok_length, DBUS_TYPE_INT32, &(pd.priv), DBUS_TYPE_UINT32, &(pd.cli_pid), DBUS_TYPE_INVALID); @@ -95,14 +112,17 @@ bool dp_unpack_pam_request(DBusMessage *msg, TALLOC_CTX *mem_ctx, return false; }
- if (pd.authtok_size != 0 && pd.authtok != NULL) { - memset(pd.authtok, 0, pd.authtok_size); - pd.authtok_size = 0; + ret = sss_authtok_set(*new_pd, &((*new_pd)->authtok), authtok_type, + authtok_data, authtok_length); + if (ret) { + DEBUG(1, ("Failed to set auth token: %d [%s]\n", ret, strerror(ret))); + return false; } - - if (pd.newauthtok_size != 0 && pd.newauthtok != NULL) { - memset(pd.newauthtok, 0, pd.newauthtok_size); - pd.newauthtok_size = 0; + ret = sss_authtok_set(*new_pd, &((*new_pd)->newauthtok), new_authtok_type, + new_authtok_data, new_authtok_length); + if (ret) { + DEBUG(1, ("Failed to set auth token: %d [%s]\n", ret, strerror(ret))); + return false; }
return true; diff --git a/src/providers/dp_pam_data_util.c b/src/providers/dp_pam_data_util.c index 889c47f00bfb49effab982ed40454b5120b84bf6..64f0d69bd0e8ebc28df958c393b40afcb5e18c31 100644 --- a/src/providers/dp_pam_data_util.c +++ b/src/providers/dp_pam_data_util.c @@ -25,26 +25,6 @@ #include "providers/data_provider.h"
-#define PD_STR_COPY(el) do { \ - if (old_pd->el != NULL) { \ - pd->el = talloc_strdup(pd, old_pd->el); \ - if (pd->el == NULL) { \ - DEBUG(1, ("talloc_strdup failed.\n")); \ - goto failed; \ - } \ - } \ -} while(0) - -#define PD_MEM_COPY(el, size) do { \ - if (old_pd->el != NULL) { \ - pd->el = talloc_memdup(pd, old_pd->el, (size)); \ - if (pd->el == NULL) { \ - DEBUG(1, ("talloc_memdup failed.\n")); \ - goto failed; \ - } \ - } \ -} while(0) - #define PAM_SAFE_ITEM(item) item ? item : "not set"
static const char *pamcmd2str(int cmd) { @@ -72,17 +52,11 @@ int pam_data_destructor(void *ptr) { struct pam_data *pd = talloc_get_type(ptr, struct pam_data);
- if (pd->authtok_size != 0 && pd->authtok != NULL) { - memset(pd->authtok, 0, pd->authtok_size); - pd->authtok_size = 0; - } + /* make sure to wipe any password from memory before freeing */ + sss_authtok_wipe_password(&pd->authtok); + sss_authtok_wipe_password(&pd->newauthtok);
- if (pd->newauthtok_size != 0 && pd->newauthtok != NULL) { - memset(pd->newauthtok, 0, pd->newauthtok_size); - pd->newauthtok_size = 0; - } - - return EOK; + return 0; }
struct pam_data *create_pam_data(TALLOC_CTX *mem_ctx) @@ -100,41 +74,72 @@ struct pam_data *create_pam_data(TALLOC_CTX *mem_ctx) return pd; }
-errno_t copy_pam_data(TALLOC_CTX *mem_ctx, struct pam_data *old_pd, - struct pam_data **new_pd) +errno_t copy_pam_data(TALLOC_CTX *mem_ctx, struct pam_data *src, + struct pam_data **dst) { struct pam_data *pd = NULL; + errno_t ret;
pd = create_pam_data(mem_ctx); if (pd == NULL) { - DEBUG(1, ("create_pam_data failed.\n")); - return ENOMEM; + ret = ENOMEM; + goto failed; }
- pd->cmd = old_pd->cmd; - pd->authtok_type = old_pd->authtok_type; - pd->authtok_size = old_pd->authtok_size; - pd->newauthtok_type = old_pd->newauthtok_type; - pd->newauthtok_size = old_pd->newauthtok_size; - pd->priv = old_pd->priv; + pd->cmd = src->cmd; + pd->priv = src->priv;
- PD_STR_COPY(domain); - PD_STR_COPY(user); - PD_STR_COPY(service); - PD_STR_COPY(tty); - PD_STR_COPY(ruser); - PD_STR_COPY(rhost); - PD_MEM_COPY(authtok, old_pd->authtok_size); - PD_MEM_COPY(newauthtok, old_pd->newauthtok_size); - pd->cli_pid = old_pd->cli_pid; + pd->domain = talloc_strdup(pd, src->domain); + if (pd->domain == NULL && src->domain != NULL) { + ret = ENOMEM; + goto failed; + } + pd->user = talloc_strdup(pd, src->user); + if (pd->user == NULL && src->user != NULL) { + ret = ENOMEM; + goto failed; + } + pd->service = talloc_strdup(pd, src->service); + if (pd->service == NULL && src->service != NULL) { + ret = ENOMEM; + goto failed; + } + pd->tty = talloc_strdup(pd, src->tty); + if (pd->tty == NULL && src->tty != NULL) { + ret = ENOMEM; + goto failed; + } + pd->ruser = talloc_strdup(pd, src->ruser); + if (pd->ruser == NULL && src->ruser != NULL) { + ret = ENOMEM; + goto failed; + } + pd->rhost = talloc_strdup(pd, src->rhost); + if (pd->rhost == NULL && src->rhost != NULL) { + ret = ENOMEM; + goto failed; + } + + pd->cli_pid = src->cli_pid; + + ret = sss_authtok_copy(pd, &src->authtok, &pd->authtok); + if (ret) { + goto failed; + } + + ret = sss_authtok_copy(pd, &src->newauthtok, &pd->newauthtok); + if (ret) { + goto failed; + }
- *new_pd = pd; + *dst = pd;
return EOK;
failed: talloc_free(pd); - return ENOMEM; + DEBUG(1, ("copy_pam_data failed: (%d) %s.\n", ret, strerror(ret))); + return ret; }
void pam_print_data(int l, struct pam_data *pd) @@ -146,10 +151,8 @@ void pam_print_data(int l, struct pam_data *pd) DEBUG(l, ("tty: %s\n", PAM_SAFE_ITEM(pd->tty))); DEBUG(l, ("ruser: %s\n", PAM_SAFE_ITEM(pd->ruser))); DEBUG(l, ("rhost: %s\n", PAM_SAFE_ITEM(pd->rhost))); - DEBUG(l, ("authtok type: %d\n", pd->authtok_type)); - DEBUG(l, ("authtok size: %d\n", pd->authtok_size)); - DEBUG(l, ("newauthtok type: %d\n", pd->newauthtok_type)); - DEBUG(l, ("newauthtok size: %d\n", pd->newauthtok_size)); + DEBUG(l, ("authtok type: %d\n", sss_authtok_get_type(&pd->authtok))); + DEBUG(l, ("newauthtok type: %d\n", sss_authtok_get_type(&pd->newauthtok))); DEBUG(l, ("priv: %d\n", pd->priv)); DEBUG(l, ("cli_pid: %d\n", pd->cli_pid)); } diff --git a/src/providers/ipa/ipa_auth.c b/src/providers/ipa/ipa_auth.c index eb62f0295cc0dc36daad9d4147556d993c7f1509..ee15afa5c83c0c68d19e169649ae6958a1553bd1 100644 --- a/src/providers/ipa/ipa_auth.c +++ b/src/providers/ipa/ipa_auth.c @@ -332,7 +332,6 @@ static void ipa_migration_flag_connect_done(struct tevent_req *req) const char **attrs; struct ldb_message *user_msg; const char *dn; - struct dp_opt_blob password; int dp_err = DP_ERR_FATAL; int ret;
@@ -374,11 +373,8 @@ static void ipa_migration_flag_connect_done(struct tevent_req *req) goto done; }
- password.data = state->pd->authtok; - password.length = state->pd->authtok_size; - req = sdap_auth_send(state, state->ev, state->sh, NULL, NULL, dn, - "password", password); + &state->pd->authtok); if (req == NULL) { DEBUG(SSSDBG_OP_FAILURE, ("sdap_auth_send failed.\n")); goto done; diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c index 5ef6cfc28625c55d850b73dc8cc621f33da1bdce..fa22575f1ce6790745b0761c1fefe9d8f6b021ad 100644 --- a/src/providers/krb5/krb5_auth.c +++ b/src/providers/krb5/krb5_auth.c @@ -278,12 +278,12 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, struct pam_data *pd, uid_t uid, int *pam_status, int *dp_err) { - char *password = NULL; + const char *password = NULL; errno_t ret;
- password = talloc_strndup(state, pd->authtok, pd->authtok_size); - if (!password) { - DEBUG(0, ("Out of memory copying password\n")); + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + if (ret != EOK) { + DEBUG(0, ("Failed to get password [%d] %s\n", ret, strerror(ret))); *pam_status = PAM_SYSTEM_ERR; *dp_err = DP_ERR_OK; return; @@ -294,7 +294,7 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, DEBUG(1, ("Offline authentication failed\n")); *pam_status = cached_login_pam_status(ret); *dp_err = DP_ERR_OK; - goto done; + return; }
ret = add_user_to_delayed_online_authentication(krb5_ctx, pd, uid); @@ -304,12 +304,6 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, } *pam_status = PAM_AUTHINFO_UNAVAIL; *dp_err = DP_ERR_OFFLINE; - -done: - if (password) { - for (i = 0; password[i]; i++) password[i] = 0; - talloc_zfree(password); - } }
static errno_t krb5_auth_prepare_ccache_file(struct krb5child_req *kr, @@ -385,16 +379,9 @@ static errno_t krb5_auth_prepare_ccache_file(struct krb5child_req *kr,
static void krb5_auth_store_creds(struct sysdb_ctx *sysdb, struct pam_data *pd) { - TALLOC_CTX *tmp_ctx; - char *password = NULL; + const char *password = NULL; int ret = EOK;
- tmp_ctx = talloc_new(NULL); - if (!tmp_ctx) { - DEBUG(0, ("Out of memory when trying to store credentials\n")); - return; - } - switch(pd->cmd) { case SSS_CMD_RENEW: /* The authtok is set to the credential cache @@ -404,42 +391,35 @@ static void krb5_auth_store_creds(struct sysdb_ctx *sysdb, struct pam_data *pd) break; case SSS_PAM_AUTHENTICATE: case SSS_PAM_CHAUTHTOK_PRELIM: - password = talloc_size(tmp_ctx, pd->authtok_size + 1); - if (password != NULL) { - memcpy(password, pd->authtok, pd->authtok_size); - password[pd->authtok_size] = '\0'; - } + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); break; case SSS_PAM_CHAUTHTOK: - password = talloc_size(tmp_ctx, pd->newauthtok_size + 1); - if (password != NULL) { - memcpy(password, pd->newauthtok, pd->newauthtok_size); - password[pd->newauthtok_size] = '\0'; - } + ret = sss_authtok_get_password(&pd->newauthtok, &password, NULL); break; default: DEBUG(0, ("unsupported PAM command [%d].\n", pd->cmd)); }
+ if (ret != EOK) { + DEBUG(0, ("Failed to get password [%d] %s\n", ret, strerror(ret))); + /* password caching failures are not fatal errors */ + return; + } + if (password == NULL) { if (pd->cmd != SSS_CMD_RENEW) { DEBUG(0, ("password not available, offline auth may not work.\n")); /* password caching failures are not fatal errors */ } - talloc_zfree(tmp_ctx); return; }
- talloc_set_destructor((TALLOC_CTX *)password, password_destructor); - ret = sysdb_cache_password(sysdb, pd->user, password); if (ret) { DEBUG(2, ("Failed to cache password, offline auth may not work." " (%d)[%s]!?\n", ret, strerror(ret))); /* password caching failures are not fatal errors */ } - - talloc_zfree(tmp_ctx); }
/* krb5_auth request */ @@ -504,9 +484,17 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx, case SSS_PAM_AUTHENTICATE: case SSS_CMD_RENEW: case SSS_PAM_CHAUTHTOK: + if (sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { + DEBUG(1, ("Missing authtok for user [%s].\n", pd->user)); + state->pam_status = PAM_SYSTEM_ERR; + state->dp_err = DP_ERR_FATAL; + ret = EINVAL; + goto done; + } break; case SSS_PAM_CHAUTHTOK_PRELIM: - if (pd->priv == 1 && pd->authtok_size == 0) { + if (pd->priv == 1 && + sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { DEBUG(4, ("Password reset by root is not supported.\n")); state->pam_status = PAM_PERM_DENIED; state->dp_err = DP_ERR_OK; diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c index 66e22f4330642189370e420d0c15bce56ca537fa..d1a42d56f1cb7137f2e21b54f6959da2fec5f6d0 100644 --- a/src/providers/krb5/krb5_child.c +++ b/src/providers/krb5/krb5_child.c @@ -950,7 +950,7 @@ done: }
static krb5_error_code get_and_save_tgt(struct krb5_req *kr, - char *password) + const char *password) { krb5_error_code kerr = 0; int ret; @@ -971,7 +971,8 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr, DEBUG(SSSDBG_TRACE_FUNC, ("Attempting kinit for realm [%s]\n",realm_name)); kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - password, sss_krb5_prompter, kr, 0, + discard_const(password), + sss_krb5_prompter, kr, 0, NULL, kr->options); if (kerr != 0) { KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); @@ -1066,8 +1067,8 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) { int ret; krb5_error_code kerr = 0; - char *pass_str = NULL; - char *newpass_str = NULL; + const char *password = NULL; + const char *newpassword = NULL; int pam_status = PAM_SYSTEM_ERR; int result_code = -1; krb5_data result_code_string; @@ -1082,20 +1083,15 @@ static errno_t changepw_child(int fd, struct krb5_req *kr)
DEBUG(SSSDBG_TRACE_LIBS, ("Password change operation\n"));
- if (kr->pd->authtok_type != SSS_AUTHTOK_TYPE_PASSWORD) { + ret = sss_authtok_get_password(&kr->pd->authtok, &password, NULL); + if (ret != EOK) { + DEBUG(1, ("Failed to fetch current password [%d] %s.\n", + ret, strerror(ret))); pam_status = PAM_CRED_INSUFFICIENT; kerr = KRB5KRB_ERR_GENERIC; goto sendresponse; }
- pass_str = talloc_strndup(kr, (const char *) kr->pd->authtok, - kr->pd->authtok_size); - if (pass_str == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - kerr = KRB5KRB_ERR_GENERIC; - goto sendresponse; - } - if (kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) { /* We do not need a password expiration warning here. */ prompter = NULL; @@ -1112,7 +1108,8 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) DEBUG(SSSDBG_TRACE_FUNC, ("Attempting kinit for realm [%s]\n",realm_name)); kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - pass_str, prompter, kr, 0, + discard_const(password), + prompter, kr, 0, SSSD_KRB5_CHANGEPW_PRINCIPAL, chagepw_options); sss_krb5_get_init_creds_opt_free(kr->ctx, chagepw_options); @@ -1121,9 +1118,7 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) goto sendresponse; }
- memset(pass_str, 0, kr->pd->authtok_size); - talloc_zfree(pass_str); - memset(kr->pd->authtok, 0, kr->pd->authtok_size); + sss_authtok_set_empty(&kr->pd->authtok);
if (kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) { DEBUG(SSSDBG_TRACE_LIBS, @@ -1134,17 +1129,18 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) goto sendresponse; }
- newpass_str = talloc_strndup(kr, (const char *) kr->pd->newauthtok, - kr->pd->newauthtok_size); - if (newpass_str == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); + ret = sss_authtok_get_password(&kr->pd->newauthtok, &newpassword, NULL); + if (ret != EOK) { + DEBUG(1, ("Failed to fetch new password [%d] %s.\n", + ret, strerror(ret))); kerr = KRB5KRB_ERR_GENERIC; goto sendresponse; }
memset(&result_code_string, 0, sizeof(krb5_data)); memset(&result_string, 0, sizeof(krb5_data)); - kerr = krb5_change_password(kr->ctx, kr->creds, newpass_str, &result_code, + kerr = krb5_change_password(kr->ctx, kr->creds, + discard_const(newpassword), &result_code, &result_code_string, &result_string);
if (kerr == KRB5_KDC_UNREACH) { @@ -1200,10 +1196,9 @@ static errno_t changepw_child(int fd, struct krb5_req *kr)
krb5_free_cred_contents(kr->ctx, kr->creds);
- kerr = get_and_save_tgt(kr, newpass_str); - memset(newpass_str, 0, kr->pd->newauthtok_size); - talloc_zfree(newpass_str); - memset(kr->pd->newauthtok, 0, kr->pd->newauthtok_size); + kerr = get_and_save_tgt(kr, newpassword); + + sss_authtok_set_empty(&kr->pd->newauthtok);
pam_status = kerr_to_status(kerr);
@@ -1220,28 +1215,21 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) { int ret; krb5_error_code kerr = 0; - char *pass_str = NULL; + const char *password = NULL; int pam_status = PAM_SYSTEM_ERR; krb5_get_init_creds_opt *chagepw_options;
DEBUG(SSSDBG_TRACE_LIBS, ("Attempting to get a TGT\n"));
- if (kr->pd->authtok_type != SSS_AUTHTOK_TYPE_PASSWORD) { + ret = sss_authtok_get_password(&kr->pd->authtok, &password, NULL); + if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Unknown authtok type\n")); pam_status = PAM_CRED_INSUFFICIENT; kerr = KRB5KRB_ERR_GENERIC; goto sendresponse; }
- pass_str = talloc_strndup(kr, (const char *) kr->pd->authtok, - kr->pd->authtok_size); - if (pass_str == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - kerr = KRB5KRB_ERR_GENERIC; - goto sendresponse; - } - - kerr = get_and_save_tgt(kr, pass_str); + kerr = get_and_save_tgt(kr, password);
/* If the password is expired the KDC will always return KRB5KDC_ERR_KEY_EXP regardless if the supplied password is correct or @@ -1264,7 +1252,8 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) }
kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - pass_str, sss_krb5_prompter, kr, 0, + discard_const(password), + sss_krb5_prompter, kr, 0, SSSD_KRB5_CHANGEPW_PRINCIPAL, chagepw_options);
@@ -1276,9 +1265,7 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) } }
- memset(pass_str, 0, kr->pd->authtok_size); - talloc_zfree(pass_str); - memset(kr->pd->authtok, 0, kr->pd->authtok_size); + sss_authtok_set_empty(&kr->pd->authtok);
pam_status = kerr_to_status(kerr);
@@ -1333,25 +1320,20 @@ static errno_t renew_tgt_child(int fd, struct krb5_req *kr) int ret; int status = PAM_AUTHTOK_ERR; int kerr; - char *ccname; + const char *ccname; krb5_ccache ccache = NULL;
DEBUG(SSSDBG_TRACE_LIBS, ("Renewing a ticket\n"));
- if (kr->pd->authtok_type != SSS_AUTHTOK_TYPE_CCFILE) { - DEBUG(1, ("Unsupported authtok type for TGT renewal [%d].\n", - kr->pd->authtok_type)); + ret = sss_authtok_get_ccfile(&kr->pd->authtok, &ccname, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + ("Unsupported authtok type for TGT renewal [%d].\n", + sss_authtok_get_type(&kr->pd->authtok))); kerr = EINVAL; goto done; }
- ccname = talloc_strndup(kr, (char *) kr->pd->authtok, kr->pd->authtok_size); - if (ccname == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - kerr = ENOMEM; - goto done; - } - kerr = krb5_cc_resolve(kr->ctx, ccname, &ccache); if (kerr != 0) { KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); @@ -1444,6 +1426,38 @@ static errno_t create_empty_ccache(int fd, struct krb5_req *kr) return ret; }
+static errno_t unpack_authtok(TALLOC_CTX *mem_ctx, struct sss_auth_token *tok, + uint8_t *buf, size_t size, size_t *p) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + errno_t ret = EOK; + + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, buf + *p, size, p); + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_length, buf + *p, size, p); + if ((*p + auth_token_length) > size) { + return EINVAL; + } + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_set_password(mem_ctx, tok, (char *)(buf + *p), 0); + break; + case SSS_AUTHTOK_TYPE_CCFILE: + ret = sss_authtok_set_ccfile(mem_ctx, tok, (char *)(buf + *p), 0); + break; + default: + return EINVAL; + } + + if (ret == EOK) { + *p += auth_token_length; + } + return ret; +} + static errno_t unpack_buffer(uint8_t *buf, size_t size, struct pam_data *pd, struct krb5_req *kr, uint32_t *offline) { @@ -1451,6 +1465,7 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size, struct pam_data *pd, uint32_t len; uint32_t validate; uint32_t different_realm; + errno_t ret;
DEBUG(SSSDBG_TRACE_LIBS, ("total buffer size: [%d]\n", size));
@@ -1491,35 +1506,26 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size, struct pam_data *pd, if (kr->keytab == NULL) return ENOMEM; p += len;
- SAFEALIGN_COPY_UINT32_CHECK(&pd->authtok_type, buf + p, size, &p); - SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p); - if ((p + len) > size) return EINVAL; - pd->authtok = (uint8_t *)talloc_strndup(pd, (char *)(buf + p), len); - if (pd->authtok == NULL) return ENOMEM; - pd->authtok_size = len + 1; - p += len; + ret = unpack_authtok(pd, &pd->authtok, buf, size, &p); + if (ret) { + return ret; + }
DEBUG(SSSDBG_CONF_SETTINGS, ("ccname: [%s] keytab: [%s]\n", kr->ccname, kr->keytab)); } else { kr->ccname = NULL; kr->keytab = NULL; - pd->authtok = NULL; - pd->authtok_size = 0; + sss_authtok_set_empty(&pd->authtok); }
if (pd->cmd == SSS_PAM_CHAUTHTOK) { - SAFEALIGN_COPY_UINT32_CHECK(&pd->newauthtok_type, buf + p, size, &p); - SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p); - - if ((p + len) > size) return EINVAL; - pd->newauthtok = (uint8_t *)talloc_strndup(pd, (char *)(buf + p), len); - if (pd->newauthtok == NULL) return ENOMEM; - pd->newauthtok_size = len + 1; - p += len; + ret = unpack_authtok(pd, &pd->newauthtok, buf, size, &p); + if (ret) { + return ret; + } } else { - pd->newauthtok = NULL; - pd->newauthtok_size = 0; + sss_authtok_set_empty(&pd->newauthtok); }
if (pd->cmd == SSS_PAM_ACCT_MGMT) { diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c index e792db3f7a6ebe7857b1ec699bc37d52ae3cad5d..5adbcf700ebf02a2aa524af3cecab51e543b4986 100644 --- a/src/providers/krb5/krb5_child_handler.c +++ b/src/providers/krb5/krb5_child_handler.c @@ -85,6 +85,43 @@ static int child_io_destructor(void *ptr) return EOK; }
+static errno_t pack_authtok(struct io_buffer *buf, size_t *rp, + struct sss_auth_token *tok) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + const char *data; + size_t len; + errno_t ret = EOK; + + auth_token_type = sss_authtok_get_type(tok); + + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + auth_token_length = 0; + data = ""; + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_get_password(tok, &data, &len); + auth_token_length = len + 1; + break; + case SSS_AUTHTOK_TYPE_CCFILE: + ret = sss_authtok_get_password(tok, &data, &len); + auth_token_length = len + 1; + break; + default: + ret = EINVAL; + } + + if (ret == EOK) { + SAFEALIGN_COPY_UINT32(&buf->data[*rp], &auth_token_type, rp); + SAFEALIGN_COPY_UINT32(&buf->data[*rp], &auth_token_length, rp); + safealign_memcpy(&buf->data[*rp], data, auth_token_length, rp); + } + + return ret; +} + static errno_t create_send_buffer(struct krb5child_req *kr, struct io_buffer **io_buf) { @@ -94,6 +131,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr, uint32_t validate; uint32_t different_realm; size_t username_len = 0; + errno_t ret;
keytab = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_KEYTAB); if (keytab == NULL) { @@ -117,11 +155,12 @@ static errno_t create_send_buffer(struct krb5child_req *kr, kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM || kr->pd->cmd == SSS_PAM_CHAUTHTOK) { buf->size += 4*sizeof(uint32_t) + strlen(kr->ccname) + strlen(keytab) + - kr->pd->authtok_size; + sss_authtok_get_size(&kr->pd->authtok); }
if (kr->pd->cmd == SSS_PAM_CHAUTHTOK) { - buf->size += 2*sizeof(uint32_t) + kr->pd->newauthtok_size; + buf->size += 2*sizeof(uint32_t) + + sss_authtok_get_size(&kr->pd->newauthtok); }
if (kr->pd->cmd == SSS_PAM_ACCT_MGMT) { @@ -157,17 +196,17 @@ static errno_t create_send_buffer(struct krb5child_req *kr, SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(keytab), &rp); safealign_memcpy(&buf->data[rp], keytab, strlen(keytab), &rp);
- SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->authtok_type, &rp); - SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->authtok_size, &rp); - safealign_memcpy(&buf->data[rp], kr->pd->authtok, - kr->pd->authtok_size, &rp); + ret = pack_authtok(buf, &rp, &kr->pd->authtok); + if (ret) { + return ret; + } }
if (kr->pd->cmd == SSS_PAM_CHAUTHTOK) { - SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->newauthtok_type, &rp); - SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->newauthtok_size, &rp); - safealign_memcpy(&buf->data[rp], kr->pd->newauthtok, - kr->pd->newauthtok_size, &rp); + ret = pack_authtok(buf, &rp, &kr->pd->newauthtok); + if (ret) { + return ret; + } }
if (kr->pd->cmd == SSS_PAM_ACCT_MGMT) { diff --git a/src/providers/krb5/krb5_delayed_online_authentication.c b/src/providers/krb5/krb5_delayed_online_authentication.c index d5dea3bb4c7661f45b6bea83cf803c7d681062cc..f95fa634c34ebee37bffb785abe4ef5b35318a82 100644 --- a/src/providers/krb5/krb5_delayed_online_authentication.c +++ b/src/providers/krb5/krb5_delayed_online_authentication.c @@ -71,27 +71,29 @@ static void authenticate_user(struct tevent_context *ev,
DEBUG_PAM_DATA(9, pd);
- if (pd->authtok == NULL || pd->authtok_size == 0) { - DEBUG(1, ("Missing authtok for user [%s].\n", pd->user)); - return; - } - #ifdef USE_KEYRING + char *password; long keysize; long keyrevoke; - int ret; - keysize = keyctl_read(pd->key_serial, (char *) pd->authtok, - pd->authtok_size); - keyrevoke = keyctl_revoke(pd->key_serial); + errno_t ret; + + keysize = keyctl_read_alloc(pd->key_serial, (void **)&password); if (keysize == -1) { ret = errno; DEBUG(1, ("keyctl_read failed [%d][%s].\n", ret, strerror(ret))); return; - } else if (keysize != pd->authtok_size) { - DEBUG(1, ("keyctl_read returned key with wrong size, " - "expect [%d] got [%d].\n", pd->authtok_size, keysize)); + } + + ret = sss_authtok_set_password(pd, &pd->authtok, password, keysize); + safezero(password, keysize); + free(password); + if (ret) { + DEBUG(1, ("failed to set password in auth token [%d][%s].\n", + ret, strerror(ret))); return; } + + keyrevoke = keyctl_revoke(pd->key_serial); if (keyrevoke == -1) { ret = errno; DEBUG(1, ("keyctl_revoke failed [%d][%s].\n", ret, strerror(ret))); @@ -244,8 +246,8 @@ errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx, return EINVAL; }
- if (pd->authtok_size == 0 || pd->authtok == NULL) { - DEBUG(1, ("Missing authtok for user [%s].\n", pd->user)); + if (sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { + DEBUG(1, ("Invalid authtok for user [%s].\n", pd->user)); return EINVAL; }
@@ -257,17 +259,29 @@ errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx,
#ifdef USE_KEYRING - new_pd->key_serial = add_key("user", new_pd->user, new_pd->authtok, - new_pd->authtok_size, KEY_SPEC_SESSION_KEYRING); + const char *password; + size_t len; + + ret = sss_authtok_get_password(&new_pd->authtok, &password, &len); + if (ret) { + DEBUG(1, ("Failed to get password [%d][%s].\n", ret, strerror(ret))); + sss_authtok_set_empty(&new_pd->authtok); + talloc_free(new_pd); + return ret; + } + + new_pd->key_serial = add_key("user", new_pd->user, password, len, + KEY_SPEC_SESSION_KEYRING); if (new_pd->key_serial == -1) { ret = errno; - DEBUG(1, ("add_key fialed [%d][%s].\n", ret, strerror(ret))); + DEBUG(1, ("add_key failed [%d][%s].\n", ret, strerror(ret))); + sss_authtok_set_empty(&new_pd->authtok); talloc_free(new_pd); return ret; } DEBUG(9, ("Saved authtok of user [%s] with serial [%ld].\n", new_pd->user, new_pd->key_serial)); - memset(new_pd->authtok, 0, new_pd->authtok_size); + sss_authtok_set_empty(&new_pd->authtok); #endif
key.type = HASH_KEY_ULONG; diff --git a/src/providers/krb5/krb5_renew_tgt.c b/src/providers/krb5/krb5_renew_tgt.c index ccb7e6af6d05121292d1152977c319daf660c9ef..4a812ab04d028961914557522423be82a1a01941 100644 --- a/src/providers/krb5/krb5_renew_tgt.c +++ b/src/providers/krb5/krb5_renew_tgt.c @@ -593,22 +593,14 @@ errno_t add_tgt_to_renew_table(struct krb5_ctx *krb5_ctx, const char *ccfile, goto done; }
- if (renew_data->pd->newauthtok_type != SSS_AUTHTOK_TYPE_EMPTY) { - talloc_zfree(renew_data->pd->newauthtok); - renew_data->pd->newauthtok_size = 0; - renew_data->pd->newauthtok_type = SSS_AUTHTOK_TYPE_EMPTY; - } + sss_authtok_set_empty(&renew_data->pd->newauthtok);
- talloc_zfree(renew_data->pd->authtok); - renew_data->pd->authtok = (uint8_t *) talloc_strdup(renew_data->pd, - renew_data->ccfile); - if (renew_data->pd->authtok == NULL) { - DEBUG(1, ("talloc_strdup failed.\n")); - ret = ENOMEM; + ret = sss_authtok_set_ccfile(renew_data->pd, &renew_data->pd->authtok, + renew_data->ccfile, 0); + if (ret) { + DEBUG(1, ("Failed to store ccfile in auth token.\n")); goto done; } - renew_data->pd->authtok_size = strlen((char *) renew_data->pd->authtok) + 1; - renew_data->pd->authtok_type = SSS_AUTHTOK_TYPE_CCFILE;
renew_data->pd->cmd = SSS_CMD_RENEW;
diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c index 32a2e04ea959a3cc81b88f5b2b19575c813e8adf..98483fee0da418523e78152861d489988eb9c6c2 100644 --- a/src/providers/ldap/ldap_auth.c +++ b/src/providers/ldap/ldap_auth.c @@ -462,7 +462,7 @@ struct auth_state { struct tevent_context *ev; struct sdap_auth_ctx *ctx; const char *username; - struct dp_opt_blob password; + struct sss_auth_token *authtok; struct sdap_service *sdap_service;
struct sdap_handle *sh; @@ -484,7 +484,7 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx, struct tevent_context *ev, struct sdap_auth_ctx *ctx, const char *username, - struct dp_opt_blob password, + struct sss_auth_token *authtok, bool try_chpass_service) { struct tevent_req *req; @@ -493,8 +493,8 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx, req = tevent_req_create(memctx, &state, struct auth_state); if (!req) return NULL;
- /* Treat a zero-length password as a failure */ - if (password.length == 0) { + /* The token must be a password token */ + if (sss_authtok_get_type(authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { state->result = SDAP_AUTH_FAILED; tevent_req_done(req); return tevent_req_post(req, ev); @@ -503,7 +503,7 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx, state->ev = ev; state->ctx = ctx; state->username = username; - state->password = password; + state->authtok = authtok; state->srv = NULL; if (try_chpass_service && ctx->chpass_service != NULL && ctx->chpass_service->name != NULL) { @@ -632,7 +632,7 @@ static void auth_connect_done(struct tevent_req *subreq)
subreq = sdap_auth_send(state, state->ev, state->sh, NULL, NULL, state->dn, - "password", state->password); + state->authtok); if (!subreq) { tevent_req_error(req, ENOMEM); return; @@ -727,8 +727,6 @@ struct sdap_pam_chpass_state { struct pam_data *pd; const char *username; char *dn; - char *password; - char *new_password; struct sdap_handle *sh;
struct sdap_auth_ctx *ctx; @@ -744,7 +742,6 @@ void sdap_pam_chpass_handler(struct be_req *breq) struct sdap_auth_ctx *ctx; struct tevent_req *subreq; struct pam_data *pd; - struct dp_opt_blob authtok; int dp_err = DP_ERR_FATAL;
ctx = talloc_get_type(breq->be_ctx->bet_info[BET_CHPASS].pvt_bet_data, @@ -758,8 +755,8 @@ void sdap_pam_chpass_handler(struct be_req *breq) goto done; }
- if (pd->priv == 1 && pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM && - pd->authtok_size == 0) { + if ((pd->priv == 1) && (pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) && + (sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD)) { DEBUG(4, ("Password reset by root is not supported.\n")); pd->pam_status = PAM_PERM_DENIED; dp_err = DP_ERR_OK; @@ -782,25 +779,9 @@ void sdap_pam_chpass_handler(struct be_req *breq) state->pd = pd; state->username = pd->user; state->ctx = ctx; - state->password = talloc_strndup(state, - (char *)pd->authtok, pd->authtok_size); - if (!state->password) goto done; - talloc_set_destructor((TALLOC_CTX *)state->password, - password_destructor);
- if (pd->cmd == SSS_PAM_CHAUTHTOK) { - state->new_password = talloc_strndup(state, - (char *)pd->newauthtok, - pd->newauthtok_size); - if (!state->new_password) goto done; - talloc_set_destructor((TALLOC_CTX *)state->new_password, - password_destructor); - } - - authtok.data = (uint8_t *)state->password; - authtok.length = strlen(state->password); - subreq = auth_send(breq, breq->be_ctx->ev, - ctx, state->username, authtok, true); + subreq = auth_send(breq, breq->be_ctx->ev, ctx, + state->username, &pd->authtok, true); if (!subreq) goto done;
tevent_req_set_callback(subreq, sdap_auth4chpass_done, state); @@ -887,18 +868,30 @@ static void sdap_auth4chpass_done(struct tevent_req *req) state->pd->pam_status = PAM_MODULE_UNKNOWN; goto done; } else { + const char *password; + const char *new_password; + + ret = sss_authtok_get_password(&state->pd->authtok, + &password, NULL); + if (ret) { + state->pd->pam_status = PAM_SYSTEM_ERR; + goto done; + } + ret = sss_authtok_get_password(&state->pd->newauthtok, + &new_password, NULL); + if (ret) { + state->pd->pam_status = PAM_SYSTEM_ERR; + goto done; + } + subreq = sdap_exop_modify_passwd_send(state, state->breq->be_ctx->ev, - state->sh, - state->dn, - state->password, - state->new_password); - + state->sh, state->dn, + password, new_password); if (!subreq) { DEBUG(2, ("Failed to change password for %s\n", state->username)); goto done; } - tevent_req_set_callback(subreq, sdap_pam_chpass_done, state); return; } @@ -1013,8 +1006,6 @@ done: struct sdap_pam_auth_state { struct be_req *breq; struct pam_data *pd; - const char *username; - struct dp_opt_blob password; };
static void sdap_pam_auth_done(struct tevent_req *req); @@ -1049,12 +1040,9 @@ void sdap_pam_auth_handler(struct be_req *breq)
state->breq = breq; state->pd = pd; - state->username = pd->user; - state->password.data = pd->authtok; - state->password.length = pd->authtok_size;
subreq = auth_send(breq, breq->be_ctx->ev, ctx, - state->username, state->password, + pd->user, &pd->authtok, pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM ? true : false); if (!subreq) goto done;
@@ -1088,6 +1076,7 @@ static void sdap_pam_auth_done(struct tevent_req *req) enum pwexpire pw_expire_type; struct be_ctx *be_ctx = state->breq->be_ctx; void *pw_expire_data; + const char *password; int dp_err = DP_ERR_OK; int ret;
@@ -1170,26 +1159,19 @@ static void sdap_pam_auth_done(struct tevent_req *req) if (result == SDAP_AUTH_SUCCESS && state->breq->be_ctx->domain->cache_credentials) {
- char *password = talloc_strndup(state, (char *) - state->password.data, - state->password.length); - /* password caching failures are not fatal errors */ - if (!password) { - DEBUG(2, ("Failed to cache password for %s\n", state->username)); - goto done; + ret = sss_authtok_get_password(&state->pd->authtok, &password, NULL); + if (ret == EOK) { + ret = sysdb_cache_password(state->breq->be_ctx->sysdb, + state->pd->user, password); } - talloc_set_destructor((TALLOC_CTX *)password, password_destructor); - - ret = sysdb_cache_password(state->breq->be_ctx->sysdb, - state->username, password);
/* password caching failures are not fatal errors */ if (ret != EOK) { DEBUG(2, ("Failed to cache password for %s\n", - state->username)); + state->pd->user)); } else { DEBUG(4, ("Password successfully cached for %s\n", - state->username)); + state->pd->user)); } goto done; } diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c index e0440625d279fbbaa1cc2e6343b73f5a247371f7..84497b75ef586b58e27cc4dc9e6b8b3244464676 100644 --- a/src/providers/ldap/sdap_async.c +++ b/src/providers/ldap/sdap_async.c @@ -502,8 +502,8 @@ struct tevent_req *sdap_exop_modify_passwd_send(TALLOC_CTX *memctx, struct tevent_context *ev, struct sdap_handle *sh, char *user_dn, - char *password, - char *new_password) + const char *password, + const char *new_password) { struct tevent_req *req = NULL; struct sdap_exop_modify_passwd_state *state; diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h index 8c16d94e6486336e92b6112cd8b5a2dff4c97957..c5dc17037cd6d2c4ae88aa60d43d517eb2958085 100644 --- a/src/providers/ldap/sdap_async.h +++ b/src/providers/ldap/sdap_async.h @@ -108,8 +108,7 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, const char *sasl_mech, const char *sasl_user, const char *user_dn, - const char *authtok_type, - struct dp_opt_blob authtok); + struct sss_auth_token *authtok);
int sdap_auth_recv(struct tevent_req *req, TALLOC_CTX *memctx, @@ -128,8 +127,8 @@ struct tevent_req *sdap_exop_modify_passwd_send(TALLOC_CTX *memctx, struct tevent_context *ev, struct sdap_handle *sh, char *user_dn, - char *password, - char *new_password); + const char *password, + const char *new_password); int sdap_exop_modify_passwd_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, enum sdap_result *result, char **user_error_msg); diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c index ff99248433026608f06fc548824fa2dd25aaacaa..da50f4ad49ab4319b309cf6861f801014ac47102 100644 --- a/src/providers/ldap/sdap_async_connection.c +++ b/src/providers/ldap/sdap_async_connection.c @@ -493,7 +493,7 @@ static struct tevent_req *simple_bind_send(TALLOC_CTX *memctx, DEBUG(4, ("Executing simple bind as: %s\n", state->user_dn));
ret = ldap_sasl_bind(state->sh->ldap, state->user_dn, LDAP_SASL_SIMPLE, - state->pw, request_controls, NULL, &msgid); + pw, request_controls, NULL, &msgid); if (ctrls[0]) ldap_control_free(ctrls[0]); if (ret == -1 || msgid == -1) { ret = ldap_get_option(state->sh->ldap, @@ -1082,18 +1082,12 @@ int sdap_kinit_recv(struct tevent_req *req, /* ==Authenticaticate-User-by-DN========================================== */
struct sdap_auth_state { - const char *user_dn; - struct berval pw; struct sdap_ppolicy_data *ppolicy; - - int result; bool is_sasl; + int result; };
static void sdap_auth_done(struct tevent_req *subreq); -static int sdap_auth_get_authtok(const char *authtok_type, - struct dp_opt_blob authtok, - struct berval *pw);
/* TODO: handle sasl_cred */ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, @@ -1102,31 +1096,14 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, const char *sasl_mech, const char *sasl_user, const char *user_dn, - const char *authtok_type, - struct dp_opt_blob authtok) + struct sss_auth_token *authtok) { struct tevent_req *req, *subreq; struct sdap_auth_state *state; - int ret;
req = tevent_req_create(memctx, &state, struct sdap_auth_state); if (!req) return NULL;
- state->user_dn = user_dn; - - ret = sdap_auth_get_authtok(authtok_type, authtok, &state->pw); - if (ret != EOK) { - if (ret == ENOSYS) { - DEBUG(1, ("Getting authtok is not supported with the " - "crypto library compiled with, authentication " - "might fail!\n")); - } else { - DEBUG(1, ("Cannot parse authtok.\n")); - tevent_req_error(req, ret); - return tevent_req_post(req, ev); - } - } - if (sasl_mech) { state->is_sasl = true; subreq = sasl_bind_send(state, ev, sh, sasl_mech, sasl_user, NULL); @@ -1135,8 +1112,27 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, return tevent_req_post(req, ev); } } else { + const char *password = NULL; + struct berval pw; + size_t pwlen; + errno_t ret; + + ret = sss_authtok_get_password(authtok, &password, &pwlen); + if (ret != EOK) { + DEBUG(1, ("Cannot parse authtok.\n")); + tevent_req_error(req, ret); + return tevent_req_post(req, ev); + } + /* Treat a zero-length password as a failure */ + if (*password == '\0') { + tevent_req_error(req, ENOENT); + return tevent_req_post(req, ev); + } + pw.bv_val = discard_const(password); + pw.bv_len = pwlen - 1; + state->is_sasl = false; - subreq = simple_bind_send(state, ev, sh, user_dn, &state->pw); + subreq = simple_bind_send(state, ev, sh, user_dn, &pw); if (!subreq) { tevent_req_error(req, ENOMEM); return tevent_req_post(req, ev); @@ -1598,6 +1594,10 @@ static void sdap_cli_auth_step(struct tevent_req *req) SDAP_SASL_MECH); const char *user_dn = dp_opt_get_string(state->opts->basic, SDAP_DEFAULT_BIND_DN); + const char *authtok_type; + struct dp_opt_blob authtok_blob; + struct sss_auth_token authtok = { 0 }; + errno_t ret;
/* Set the LDAP expiration time * If SASL has already set it, use the sooner of the two @@ -1620,17 +1620,31 @@ static void sdap_cli_auth_step(struct tevent_req *req) return; }
- subreq = sdap_auth_send(state, - state->ev, - state->sh, - sasl_mech, + authtok_type = dp_opt_get_string(state->opts->basic, + SDAP_DEFAULT_AUTHTOK_TYPE); + if (authtok_type != NULL) { + if (strcasecmp(authtok_type, "password") != 0) { + DEBUG(SSSDBG_TRACE_LIBS, ("Invalid authtoken type\n")); + tevent_req_error(req, EINVAL); + return; + } + authtok_blob = dp_opt_get_blob(state->opts->basic, + SDAP_DEFAULT_AUTHTOK); + + ret = sss_authtok_set_password(state, &authtok, + (const char *)authtok_blob.data, + authtok_blob.length); + if (ret) { + tevent_req_error(req, ret); + return; + } + } + + subreq = sdap_auth_send(state, state->ev, + state->sh, sasl_mech, dp_opt_get_string(state->opts->basic, - SDAP_SASL_AUTHID), - user_dn, - dp_opt_get_string(state->opts->basic, - SDAP_DEFAULT_AUTHTOK_TYPE), - dp_opt_get_blob(state->opts->basic, - SDAP_DEFAULT_AUTHTOK)); + SDAP_SASL_AUTHID), + user_dn, &authtok); if (!subreq) { tevent_req_error(req, ENOMEM); return; diff --git a/src/providers/proxy/proxy.h b/src/providers/proxy/proxy.h index cea03382517231cdf2b96069ab93dfb7967b46a6..962cb28fc7d6362c45d268f289ffbce103a6e738 100644 --- a/src/providers/proxy/proxy.h +++ b/src/providers/proxy/proxy.h @@ -89,11 +89,8 @@ struct proxy_nss_ops { };
struct authtok_conv { - uint32_t authtok_size; - uint8_t *authtok; - - uint32_t newauthtok_size; - uint8_t *newauthtok; + struct sss_auth_token authtok; + struct sss_auth_token newauthtok;
bool sent_old; }; diff --git a/src/providers/proxy/proxy_auth.c b/src/providers/proxy/proxy_auth.c index 8088283fa8147f75b7d8eb4c83c63208163c9375..3430f38b282eff2da24735f8d635a952edde8888 100644 --- a/src/providers/proxy/proxy_auth.c +++ b/src/providers/proxy/proxy_auth.c @@ -712,7 +712,7 @@ static void proxy_child_done(struct tevent_req *req) struct proxy_client_ctx *client_ctx = tevent_req_callback_data(req, struct proxy_client_ctx); struct pam_data *pd = NULL; - char *password; + const char *password; int ret; struct tevent_immediate *imm;
@@ -747,17 +747,15 @@ static void proxy_child_done(struct tevent_req *req)
/* Check if we need to save the cached credentials */ if ((pd->cmd == SSS_PAM_AUTHENTICATE || pd->cmd == SSS_PAM_CHAUTHTOK) && - pd->pam_status == PAM_SUCCESS && - client_ctx->be_req->be_ctx->domain->cache_credentials) { - password = talloc_strndup(client_ctx->be_req, - (char *) pd->authtok, - pd->authtok_size); - if (!password) { + (pd->pam_status == PAM_SUCCESS) && + client_ctx->be_req->be_ctx->domain->cache_credentials) { + + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + if (ret) { /* password caching failures are not fatal errors */ DEBUG(2, ("Failed to cache password\n")); goto done; } - talloc_set_destructor((TALLOC_CTX *)password, password_destructor);
ret = sysdb_cache_password(client_ctx->be_req->be_ctx->sysdb, pd->user, password); diff --git a/src/providers/proxy/proxy_child.c b/src/providers/proxy/proxy_child.c index c575948a7036d9b73d93bd00e111834b12d28e7d..556dbf9b5488d75f0fa60386958f61b95d61fba2 100644 --- a/src/providers/proxy/proxy_child.c +++ b/src/providers/proxy/proxy_child.c @@ -80,6 +80,9 @@ static int proxy_internal_conv(int num_msg, const struct pam_message **msgm, int i; struct pam_response *reply; struct authtok_conv *auth_data; + const char *password; + size_t pwlen; + errno_t ret;
auth_data = talloc_get_type(appdata_ptr, struct authtok_conv);
@@ -94,11 +97,13 @@ static int proxy_internal_conv(int num_msg, const struct pam_message **msgm, case PAM_PROMPT_ECHO_OFF: DEBUG(4, ("Conversation message: [%s]\n", msgm[i]->msg)); reply[i].resp_retcode = 0; - reply[i].resp = calloc(auth_data->authtok_size + 1, - sizeof(char)); + + ret = sss_authtok_get_password(&auth_data->authtok, + &password, &pwlen); + if (ret) goto failed; + reply[i].resp = calloc(pwlen + 1, sizeof(char)); if (reply[i].resp == NULL) goto failed; - memcpy(reply[i].resp, auth_data->authtok, - auth_data->authtok_size); + memcpy(reply[i].resp, password, pwlen + 1);
break; default: @@ -124,6 +129,9 @@ static int proxy_chauthtok_conv(int num_msg, const struct pam_message **msgm, int i; struct pam_response *reply; struct authtok_conv *auth_data; + const char *password; + size_t pwlen; + errno_t ret;
auth_data = talloc_get_type(appdata_ptr, struct authtok_conv);
@@ -141,20 +149,23 @@ static int proxy_chauthtok_conv(int num_msg, const struct pam_message **msgm, reply[i].resp_retcode = 0; if (!auth_data->sent_old) { /* The first prompt will be asking for the old authtok */ - reply[i].resp = calloc(auth_data->authtok_size + 1, - sizeof(char)); + ret = sss_authtok_get_password(&auth_data->authtok, + &password, &pwlen); + if (ret) goto failed; + reply[i].resp = calloc(pwlen + 1, sizeof(char)); if (reply[i].resp == NULL) goto failed; - memcpy(reply[i].resp, auth_data->authtok, - auth_data->authtok_size); + memcpy(reply[i].resp, password, pwlen + 1); auth_data->sent_old = true; } else { /* Subsequent prompts are looking for the new authtok */ - reply[i].resp = calloc(auth_data->newauthtok_size + 1, - sizeof(char)); + ret = sss_authtok_get_password(&auth_data->newauthtok, + &password, &pwlen); + if (ret) goto failed; + reply[i].resp = calloc(pwlen + 1, sizeof(char)); if (reply[i].resp == NULL) goto failed; - memcpy(reply[i].resp, auth_data->newauthtok, - auth_data->newauthtok_size); + memcpy(reply[i].resp, password, pwlen + 1); + auth_data->sent_old = true; }
break; @@ -213,8 +224,8 @@ static errno_t call_pam_stack(const char *pam_target, struct pam_data *pd) } switch (pd->cmd) { case SSS_PAM_AUTHENTICATE: - auth_data->authtok_size = pd->authtok_size; - auth_data->authtok = pd->authtok; + sss_authtok_copy(auth_data, &pd->authtok, + &auth_data->authtok); pam_status = pam_authenticate(pamh, 0); break; case SSS_PAM_SETCRED: @@ -230,21 +241,21 @@ static errno_t call_pam_stack(const char *pam_target, struct pam_data *pd) pam_status=pam_close_session(pamh, 0); break; case SSS_PAM_CHAUTHTOK: - auth_data->authtok_size = pd->authtok_size; - auth_data->authtok = pd->authtok; + sss_authtok_copy(auth_data, &pd->authtok, + &auth_data->authtok); if (pd->priv != 1) { pam_status = pam_authenticate(pamh, 0); auth_data->sent_old = false; if (pam_status != PAM_SUCCESS) break; } - auth_data->newauthtok_size = pd->newauthtok_size; - auth_data->newauthtok = pd->newauthtok; + sss_authtok_copy(auth_data, &pd->newauthtok, + &auth_data->newauthtok); pam_status = pam_chauthtok(pamh, 0); break; case SSS_PAM_CHAUTHTOK_PRELIM: if (pd->priv != 1) { - auth_data->authtok_size = pd->authtok_size; - auth_data->authtok = pd->authtok; + sss_authtok_copy(auth_data, &pd->authtok, + &auth_data->authtok); pam_status = pam_authenticate(pamh, 0); } else { pam_status = PAM_SUCCESS; diff --git a/src/responder/pam/pam_LOCAL_domain.c b/src/responder/pam/pam_LOCAL_domain.c index 71446b4f8da53bfe4c0707621fafb228da5f808c..23eb7a2a8ddd3ae4480030633be867564b7f59f2 100644 --- a/src/responder/pam/pam_LOCAL_domain.c +++ b/src/responder/pam/pam_LOCAL_domain.c @@ -154,22 +154,19 @@ static void do_pam_acct_mgmt(struct LOCAL_request *lreq) static void do_pam_chauthtok(struct LOCAL_request *lreq) { int ret; - char *newauthtok; + const char *password; char *salt; char *new_hash; struct pam_data *pd;
pd = lreq->preq->pd;
- newauthtok = talloc_strndup(lreq, (char *) pd->newauthtok, - pd->newauthtok_size); - NULL_CHECK_OR_JUMP(newauthtok, ("talloc_strndup failed.\n"), lreq->error, - ENOMEM, done); - memset(pd->newauthtok, 0, pd->newauthtok_size); - - if (strlen(newauthtok) == 0) { + ret = sss_authtok_get_password(&pd->newauthtok, &password, NULL); + if (ret) { /* TODO: should we allow null passwords via a config option ? */ - DEBUG(1, ("Empty passwords are not allowed!\n")); + if (ret == ENOENT) { + DEBUG(1, ("Empty passwords are not allowed!\n")); + } lreq->error = EINVAL; goto done; } @@ -179,11 +176,10 @@ static void do_pam_chauthtok(struct LOCAL_request *lreq) lreq->error, ret, done); DEBUG(4, ("Using salt [%s]\n", salt));
- ret = s3crypt_sha512(lreq, newauthtok, salt, &new_hash); + ret = s3crypt_sha512(lreq, password, salt, &new_hash); NEQ_CHECK_OR_JUMP(ret, EOK, ("Hash generation failed.\n"), lreq->error, ret, done); DEBUG(4, ("New hash [%s]\n", new_hash)); - memset(newauthtok, 0, pd->newauthtok_size);
lreq->mod_attrs = sysdb_new_attrs(lreq); NULL_CHECK_OR_JUMP(lreq->mod_attrs, ("sysdb_new_attrs failed.\n"), @@ -204,7 +200,7 @@ static void do_pam_chauthtok(struct LOCAL_request *lreq) lreq->error, ret, done);
done: - return; + sss_authtok_set_empty(&pd->newauthtok); }
int LOCAL_pam_handler(struct pam_auth_req *preq) @@ -223,9 +219,9 @@ int LOCAL_pam_handler(struct pam_auth_req *preq) NULL}; struct ldb_result *res; const char *username = NULL; - const char *password = NULL; + const char *pwdhash = NULL; char *new_hash = NULL; - char *authtok = NULL; + const char *password; struct pam_data *pd = preq->pd; int ret;
@@ -287,25 +283,22 @@ int LOCAL_pam_handler(struct pam_auth_req *preq) DEBUG(4, ("allowing root to reset a password.\n")); break; } - authtok = talloc_strndup(lreq, (char *) pd->authtok, - pd->authtok_size); - NULL_CHECK_OR_JUMP(authtok, ("talloc_strndup failed.\n"), - lreq->error, ENOMEM, done); - memset(pd->authtok, 0, pd->authtok_size); + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + NEQ_CHECK_OR_JUMP(ret, EOK, ("Failed to get password.\n"), + lreq->error, ret, done);
- password = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_PWD, NULL); - NULL_CHECK_OR_JUMP(password, ("No password stored.\n"), + pwdhash = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_PWD, NULL); + NULL_CHECK_OR_JUMP(pwdhash, ("No password stored.\n"), lreq->error, LDB_ERR_NO_SUCH_ATTRIBUTE, done); - DEBUG(4, ("user: [%s], password hash: [%s]\n", username, password)); + DEBUG(4, ("user: [%s], password hash: [%s]\n", username, pwdhash));
- ret = s3crypt_sha512(lreq, authtok, password, &new_hash); - memset(authtok, 0, pd->authtok_size); + ret = s3crypt_sha512(lreq, password, pwdhash, &new_hash); NEQ_CHECK_OR_JUMP(ret, EOK, ("nss_sha512_crypt failed.\n"), lreq->error, ret, done);
DEBUG(4, ("user: [%s], new hash: [%s]\n", username, new_hash));
- if (strcmp(new_hash, password) != 0) { + if (strcmp(new_hash, pwdhash) != 0) { DEBUG(1, ("Passwords do not match.\n")); do_failed_login(lreq); goto done; @@ -338,13 +331,8 @@ int LOCAL_pam_handler(struct pam_auth_req *preq) }
done: - if (pd->authtok != NULL) - memset(pd->authtok, 0, pd->authtok_size); - if (authtok != NULL) - memset(authtok, 0, pd->authtok_size); - if (pd->newauthtok != NULL) - memset(pd->newauthtok, 0, pd->newauthtok_size); - + sss_authtok_set_empty(&pd->newauthtok); + sss_authtok_set_empty(&pd->authtok); prepare_reply(lreq); return EOK; } diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index ed7438f8d1509568bcd12bbbe7ab73984780bcdd..813894d39767248f74addac8596890ba7213a352 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -49,21 +49,38 @@ enum pam_verbosity {
static void pam_reply(struct pam_auth_req *preq);
-static int extract_authtok(uint32_t *type, uint32_t *size, uint8_t **tok, - size_t data_size, uint8_t *body, size_t blen, - size_t *c) { +static int extract_authtok_v2(TALLOC_CTX *mem_ctx, struct sss_auth_token *tok, + size_t data_size, uint8_t *body, size_t blen, + size_t *c) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + uint8_t *auth_token_data; + int ret = EOK;
if (data_size < sizeof(uint32_t) || *c+data_size > blen || SIZE_T_OVERFLOW(*c, data_size)) return EINVAL; - *size = data_size - sizeof(uint32_t);
- SAFEALIGN_COPY_UINT32_CHECK(type, &body[*c], blen, c); + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, &body[*c], blen, c); + auth_token_length = data_size - sizeof(uint32_t); + auth_token_data = body+(*c);
- *tok = body+(*c); + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_set_password(mem_ctx, tok, + (const char *)auth_token_data, + auth_token_length); + break; + default: + return EINVAL; + }
- *c += (*size); + *c += auth_token_length;
- return EOK; + return ret; }
static int extract_string(char **var, size_t size, uint8_t *body, size_t blen, @@ -185,14 +202,13 @@ static int pam_parse_in_data_v2(struct sss_domain_info *domains, if (ret != EOK) return ret; break; case SSS_PAM_ITEM_AUTHTOK: - ret = extract_authtok(&pd->authtok_type, &pd->authtok_size, - &pd->authtok, size, body, blen, &c); + ret = extract_authtok_v2(pd, &pd->authtok, + size, body, blen, &c); if (ret != EOK) return ret; break; case SSS_PAM_ITEM_NEWAUTHTOK: - ret = extract_authtok(&pd->newauthtok_type, - &pd->newauthtok_size, - &pd->newauthtok, size, body, blen, &c); + ret = extract_authtok_v2(pd, &pd->newauthtok, + size, body, blen, &c); if (ret != EOK) return ret; break; default: @@ -232,14 +248,44 @@ static int pam_parse_in_data_v3(struct sss_domain_info *domains, return EOK; }
+static int extract_authtok_v1(TALLOC_CTX *mem_ctx, struct sss_auth_token *tok, + uint8_t *body, size_t blen, size_t *c) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + uint8_t *auth_token_data; + int ret = EOK; + + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, &body[*c], blen, c); + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_length, &body[*c], blen, c); + auth_token_data = body+(*c); + + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_set_password(mem_ctx, tok, + (const char *)auth_token_data, + auth_token_length); + break; + default: + return EINVAL; + } + + *c += auth_token_length; + + return ret; +} + static int pam_parse_in_data(struct sss_domain_info *domains, const char *default_domain, struct pam_data *pd, uint8_t *body, size_t blen) { - int start; - int end; - int last; + size_t start; + size_t end; + size_t last; int ret;
last = blen - 1; @@ -269,45 +315,15 @@ static int pam_parse_in_data(struct sss_domain_info *domains, if (body[end++] != '\0') return EINVAL; pd->rhost = (char *) &body[start];
- start = end; - pd->authtok_type = (int) body[start]; - - start += sizeof(uint32_t); - pd->authtok_size = (int) body[start]; - if (pd->authtok_size >= blen) return EINVAL; - - start += sizeof(uint32_t); - end = start + pd->authtok_size; - if (pd->authtok_size == 0) { - pd->authtok = NULL; - } else { - if (end <= blen) { - pd->authtok = (uint8_t *) &body[start]; - } else { - DEBUG(1, ("Invalid authtok size: %d\n", pd->authtok_size)); - return EINVAL; - } + ret = extract_authtok_v1(pd, &pd->authtok, body, blen, &end); + if (ret) { + DEBUG(1, ("Invalid auth token\n")); + return ret; } - - start = end; - pd->newauthtok_type = (int) body[start]; - - start += sizeof(uint32_t); - pd->newauthtok_size = (int) body[start]; - if (pd->newauthtok_size >= blen) return EINVAL; - - start += sizeof(uint32_t); - end = start + pd->newauthtok_size; - - if (pd->newauthtok_size == 0) { - pd->newauthtok = NULL; - } else { - if (end <= blen) { - pd->newauthtok = (uint8_t *) &body[start]; - } else { - DEBUG(1, ("Invalid newauthtok size: %d\n", pd->newauthtok_size)); - return EINVAL; - } + ret = extract_authtok_v1(pd, &pd->newauthtok, body, blen, &end); + if (ret) { + DEBUG(1, ("Invalid new auth token\n")); + return ret; }
DEBUG_PAM_DATA(4, pd); @@ -763,9 +779,9 @@ static void pam_reply(struct pam_auth_req *preq) goto done; }
- password = talloc_strndup(preq, pd->authtok, pd->authtok_size); - if (!password) { - DEBUG(0, ("Fatal: Out of memory copying password\n")); + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + if (ret) { + DEBUG(0, ("Failed to get password.\n")); goto done; }
@@ -775,10 +791,6 @@ static void pam_reply(struct pam_auth_req *preq) &exp_date, &delay_until);
pam_handle_cached_login(preq, ret, exp_date, delay_until); - if (password) { - for (i = 0; password[i]; i++) password[i] = 0; - talloc_zfree(password); - } return; } break; diff --git a/src/tests/krb5_child-test.c b/src/tests/krb5_child-test.c index 34d025b77b27a27e6131c1895c6c02644f921e5d..a72a3519985292456db6b9bbf9bccdcf678068a6 100644 --- a/src/tests/krb5_child-test.c +++ b/src/tests/krb5_child-test.c @@ -167,6 +167,9 @@ create_dummy_pam_data(TALLOC_CTX *mem_ctx, const char *user, const char *password) { struct pam_data *pd; + const char *authtok; + size_t authtok_len; + errno_t ret;
pd = talloc_zero(mem_ctx, struct pam_data); if (!pd) goto fail; @@ -175,12 +178,12 @@ create_dummy_pam_data(TALLOC_CTX *mem_ctx, const char *user, pd->user = talloc_strdup(pd, user); if (!pd->user) goto fail;
- pd->authtok = discard_const(talloc_strdup(pd, password)); - if (!pd->authtok) goto fail; - pd->authtok_size = strlen(password); - pd->authtok_type = SSS_AUTHTOK_TYPE_PASSWORD; + ret = sss_authtok_set_password(pd, &pd->authtok, password, 0); + if (ret) goto fail; + + (void)sss_authtok_get_password(&pd->authtok, &authtok, &authtok_len); DEBUG(SSSDBG_FUNC_DATA, ("Authtok [%s] len [%d]\n", - pd->authtok, pd->authtok_size)); + authtok, (int)authtok_len));
return pd;
On 12/04/2012 12:10 AM, Simo Sorce wrote:
Sorry for the previous non-building rebase, my fault, it was just a rebase silently working but generating errors as the underlying code was slightly changed.
Additional fixes for patch 3 as per PAvel comment. Couldn;t move the enum definition because it is use by pam_sss.c too and that's in the client which can;t include authtok.c
Builds, but haven;t re-tested due to time constraints.
Simo.
Simo Sorce (4): Code can only check for cached passwords Add function to safely wipe memory. Add authtok utility functions. Change pam data auth tokens.
Makefile.am | 4 + src/db/sysdb.h | 3 +- src/db/sysdb_ops.c | 13 +-- src/providers/data_provider.h | 9 +- src/providers/dp_auth_util.c | 76 +++++--- src/providers/dp_pam_data_util.c | 113 ++++++------ src/providers/ipa/ipa_auth.c | 6 +- src/providers/krb5/krb5_auth.c | 55 +++--- src/providers/krb5/krb5_child.c | 148 ++++++++------- src/providers/krb5/krb5_child_handler.c | 59 +++++- .../krb5/krb5_delayed_online_authentication.c | 50 ++++-- src/providers/krb5/krb5_renew_tgt.c | 18 +-- src/providers/ldap/ldap_auth.c | 90 ++++------ src/providers/ldap/sdap_async.c | 4 +- src/providers/ldap/sdap_async.h | 7 +- src/providers/ldap/sdap_async_connection.c | 88 +++++---- src/providers/proxy/proxy.h | 7 +- src/providers/proxy/proxy_auth.c | 14 +- src/providers/proxy/proxy_child.c | 51 +++-- src/responder/pam/pam_LOCAL_domain.c | 52 ++---- src/responder/pam/pamsrv_cmd.c | 159 +++++++++------- src/tests/krb5_child-test.c | 13 +- src/tests/sysdb-tests.c | 6 +- src/util/authtok.c | 194 ++++++++++++++++++++ src/util/authtok.h | 180 ++++++++++++++++++ src/util/util.c | 9 + src/util/util.h | 9 + 27 files changed, 950 insertions(+), 487 deletions(-) create mode 100644 src/util/authtok.c create mode 100644 src/util/authtok.h
sssd-devel mailing list sssd-devel@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/sssd-devel
Warnings during compilation...
src/util/authtok.c: In function 'sss_authtok_set': src/util/authtok.c:164:1: error: control reaches end of non-void function [-Werror=return-type] src/util/authtok.c: In function 'sss_authtok_get_ccfile': src/util/authtok.c:75:1: error: control reaches end of non-void function [-Werror=return-type] src/util/authtok.c: In function 'sss_authtok_get_password': src/util/authtok.c:58:1: error: control reaches end of non-void function [-Werror=return-type] src/util/authtok.c: In function 'sss_authtok_get_size': src/util/authtok.c:36:1: error: control reaches end of non-void function [-Werror=return-type] cc1: all warnings being treated as errors
On Tue, 2012-12-04 at 11:18 +0100, Pavel Březina wrote:
On 12/04/2012 12:10 AM, Simo Sorce wrote:
Sorry for the previous non-building rebase, my fault, it was just a rebase silently working but generating errors as the underlying code was slightly changed.
Additional fixes for patch 3 as per PAvel comment. Couldn;t move the enum definition because it is use by pam_sss.c too and that's in the client which can;t include authtok.c
Builds, but haven;t re-tested due to time constraints.
Simo.
Simo Sorce (4): Code can only check for cached passwords Add function to safely wipe memory. Add authtok utility functions. Change pam data auth tokens.
Makefile.am | 4 + src/db/sysdb.h | 3 +- src/db/sysdb_ops.c | 13 +-- src/providers/data_provider.h | 9 +- src/providers/dp_auth_util.c | 76 +++++--- src/providers/dp_pam_data_util.c | 113 ++++++------ src/providers/ipa/ipa_auth.c | 6 +- src/providers/krb5/krb5_auth.c | 55 +++--- src/providers/krb5/krb5_child.c | 148 ++++++++------- src/providers/krb5/krb5_child_handler.c | 59 +++++- .../krb5/krb5_delayed_online_authentication.c | 50 ++++-- src/providers/krb5/krb5_renew_tgt.c | 18 +-- src/providers/ldap/ldap_auth.c | 90 ++++------ src/providers/ldap/sdap_async.c | 4 +- src/providers/ldap/sdap_async.h | 7 +- src/providers/ldap/sdap_async_connection.c | 88 +++++---- src/providers/proxy/proxy.h | 7 +- src/providers/proxy/proxy_auth.c | 14 +- src/providers/proxy/proxy_child.c | 51 +++-- src/responder/pam/pam_LOCAL_domain.c | 52 ++---- src/responder/pam/pamsrv_cmd.c | 159 +++++++++------- src/tests/krb5_child-test.c | 13 +- src/tests/sysdb-tests.c | 6 +- src/util/authtok.c | 194 ++++++++++++++++++++ src/util/authtok.h | 180 ++++++++++++++++++ src/util/util.c | 9 + src/util/util.h | 9 + 27 files changed, 950 insertions(+), 487 deletions(-) create mode 100644 src/util/authtok.c create mode 100644 src/util/authtok.h
sssd-devel mailing list sssd-devel@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/sssd-devel
Warnings during compilation...
src/util/authtok.c: In function 'sss_authtok_set': src/util/authtok.c:164:1: error: control reaches end of non-void function [-Werror=return-type] src/util/authtok.c: In function 'sss_authtok_get_ccfile': src/util/authtok.c:75:1: error: control reaches end of non-void function [-Werror=return-type] src/util/authtok.c: In function 'sss_authtok_get_password': src/util/authtok.c:58:1: error: control reaches end of non-void function [-Werror=return-type] src/util/authtok.c: In function 'sss_authtok_get_size': src/util/authtok.c:36:1: error: control reaches end of non-void function [-Werror=return-type] cc1: all warnings being treated as errors
This is odd, it didn't complain here ... seem like here the compiler did not realize that all possible enum cases are intercepted in the switch/case statements I changed to avoid the 'default' and does not see they all return ... oh well I'll add an additional return to silence it.
Simo.
Fixed switch/case-return errors. The rest is the same.
Simo Sorce (4): Code can only check for cached passwords Add function to safely wipe memory. Add authtok utility functions. Change pam data auth tokens.
Makefile.am | 4 + src/db/sysdb.h | 3 +- src/db/sysdb_ops.c | 13 +-- src/providers/data_provider.h | 9 +- src/providers/dp_auth_util.c | 76 +++++--- src/providers/dp_pam_data_util.c | 113 ++++++------ src/providers/ipa/ipa_auth.c | 6 +- src/providers/krb5/krb5_auth.c | 55 +++--- src/providers/krb5/krb5_child.c | 148 ++++++++------- src/providers/krb5/krb5_child_handler.c | 59 +++++- .../krb5/krb5_delayed_online_authentication.c | 50 +++-- src/providers/krb5/krb5_renew_tgt.c | 18 +-- src/providers/ldap/ldap_auth.c | 90 ++++------ src/providers/ldap/sdap_async.c | 4 +- src/providers/ldap/sdap_async.h | 7 +- src/providers/ldap/sdap_async_connection.c | 88 +++++---- src/providers/proxy/proxy.h | 7 +- src/providers/proxy/proxy_auth.c | 14 +- src/providers/proxy/proxy_child.c | 51 +++-- src/responder/pam/pam_LOCAL_domain.c | 52 ++--- src/responder/pam/pamsrv_cmd.c | 159 +++++++++------- src/tests/krb5_child-test.c | 13 +- src/tests/sysdb-tests.c | 6 +- src/util/authtok.c | 202 ++++++++++++++++++++ src/util/authtok.h | 180 +++++++++++++++++ src/util/util.c | 9 + src/util/util.h | 9 + 27 files changed, 958 insertions(+), 487 deletions(-) create mode 100644 src/util/authtok.c create mode 100644 src/util/authtok.h
Make it clear to the API users that we can not take arbitrary auth tokens. We can only take a password for now so simplify and clarify the interface. --- src/db/sysdb.h | 3 +-- src/db/sysdb_ops.c | 12 +----------- src/providers/krb5/krb5_auth.c | 21 +++++++++++++++++---- src/responder/pam/pamsrv_cmd.c | 39 ++++++++++++++++++++++++--------------- src/tests/sysdb-tests.c | 6 ++---- 5 files changed, 45 insertions(+), 36 deletions(-)
diff --git a/src/db/sysdb.h b/src/db/sysdb.h index ed00c165952aa80102b88c9e857355f2ef27d570..892414797304a1ba86a041279aea9bcafe1fd3cd 100644 --- a/src/db/sysdb.h +++ b/src/db/sysdb.h @@ -778,8 +778,7 @@ errno_t check_failed_login_attempts(struct confdb_ctx *cdb, time_t *delayed_until); int sysdb_cache_auth(struct sysdb_ctx *sysdb, const char *name, - const uint8_t *authtok, - size_t authtok_size, + const char *password, struct confdb_ctx *cdb, bool just_check, time_t *_expire_date, diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c index 80a323b12901b40f6df0c4cd0f0b23b4cf2cf2b2..e213023e3f1f1342984b7b2464a23a4544df9010 100644 --- a/src/db/sysdb_ops.c +++ b/src/db/sysdb_ops.c @@ -2674,8 +2674,7 @@ done:
int sysdb_cache_auth(struct sysdb_ctx *sysdb, const char *name, - const uint8_t *authtok, - size_t authtok_size, + const char *password, struct confdb_ctx *cdb, bool just_check, time_t *_expire_date, @@ -2690,7 +2689,6 @@ int sysdb_cache_auth(struct sysdb_ctx *sysdb, struct ldb_message *ldb_msg; const char *userhash; char *comphash; - char *password = NULL; uint64_t lastLogin = 0; int cred_expiration; uint32_t failed_login_attempts = 0; @@ -2776,13 +2774,6 @@ int sysdb_cache_auth(struct sysdb_ctx *sysdb,
/* TODO: verify user account (disabled, expired ...) */
- password = talloc_strndup(tmp_ctx, (const char *)authtok, authtok_size); - if (password == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - ret = ENOMEM; - goto done; - } - userhash = ldb_msg_find_attr_as_string(ldb_msg, SYSDB_CACHEDPWD, NULL); if (userhash == NULL || *userhash == '\0') { DEBUG(4, ("Cached credentials not available.\n")); @@ -2866,7 +2857,6 @@ done: if (_delayed_until != NULL) { *_delayed_until = delayed_until; } - if (password) for (i = 0; password[i]; i++) password[i] = 0; if (ret) { ldb_transaction_cancel(sysdb->ldb); } else { diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c index 7104b3127e04891fed7370a6241c60865372632b..5ef6cfc28625c55d850b73dc8cc621f33da1bdce 100644 --- a/src/providers/krb5/krb5_auth.c +++ b/src/providers/krb5/krb5_auth.c @@ -278,16 +278,23 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, struct pam_data *pd, uid_t uid, int *pam_status, int *dp_err) { + char *password = NULL; errno_t ret;
- ret = sysdb_cache_auth(sysdb, pd->user, pd->authtok, - pd->authtok_size, cdb, true, NULL, - NULL); + password = talloc_strndup(state, pd->authtok, pd->authtok_size); + if (!password) { + DEBUG(0, ("Out of memory copying password\n")); + *pam_status = PAM_SYSTEM_ERR; + *dp_err = DP_ERR_OK; + return; + } + + ret = sysdb_cache_auth(sysdb, pd->user, password, cdb, true, NULL, NULL); if (ret != EOK) { DEBUG(1, ("Offline authentication failed\n")); *pam_status = cached_login_pam_status(ret); *dp_err = DP_ERR_OK; - return; + goto done; }
ret = add_user_to_delayed_online_authentication(krb5_ctx, pd, uid); @@ -297,6 +304,12 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, } *pam_status = PAM_AUTHINFO_UNAVAIL; *dp_err = DP_ERR_OFFLINE; + +done: + if (password) { + for (i = 0; password[i]; i++) password[i] = 0; + talloc_zfree(password); + } }
static errno_t krb5_auth_prepare_ccache_file(struct krb5child_req *kr, diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index 4269642206cc0295c0046de4e59a3ad8f1044d1a..ed7438f8d1509568bcd12bbbe7ab73984780bcdd 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -733,7 +733,6 @@ static void pam_reply(struct pam_auth_req *preq) struct timeval tv; struct tevent_timer *te; struct pam_data *pd; - struct sysdb_ctx *sysdb; struct pam_ctx *pctx; uint32_t user_info_type; time_t exp_date = -1; @@ -753,24 +752,34 @@ static void pam_reply(struct pam_auth_req *preq) if ((preq->domain != NULL) && (preq->domain->cache_credentials == true) && (pd->offline_auth == false)) { + const char *password = NULL;
- /* do auth with offline credentials */ - pd->offline_auth = true; + /* do auth with offline credentials */ + pd->offline_auth = true;
- sysdb = preq->domain->sysdb; - if (sysdb == NULL) { - DEBUG(0, ("Fatal: Sysdb CTX not found for " - "domain [%s]!\n", preq->domain->name)); - goto done; - } + if (preq->domain->sysdb == NULL) { + DEBUG(0, ("Fatal: Sysdb CTX not found for domain" + " [%s]!\n", preq->domain->name)); + goto done; + }
- ret = sysdb_cache_auth(sysdb, pd->user, - pd->authtok, pd->authtok_size, - pctx->rctx->cdb, false, - &exp_date, &delay_until); + password = talloc_strndup(preq, pd->authtok, pd->authtok_size); + if (!password) { + DEBUG(0, ("Fatal: Out of memory copying password\n")); + goto done; + }
- pam_handle_cached_login(preq, ret, exp_date, delay_until); - return; + ret = sysdb_cache_auth(preq->domain->sysdb, + pd->user, password, + pctx->rctx->cdb, false, + &exp_date, &delay_until); + + pam_handle_cached_login(preq, ret, exp_date, delay_until); + if (password) { + for (i = 0; password[i]; i++) password[i] = 0; + talloc_zfree(password); + } + return; } break; case SSS_PAM_CHAUTHTOK_PRELIM: diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c index 74b75233d7a5cf027ffdf581cbc9942ba2cc2b95..06cda816d79986d099d24457c40af7264b5a1a44 100644 --- a/src/tests/sysdb-tests.c +++ b/src/tests/sysdb-tests.c @@ -1576,8 +1576,7 @@ static void cached_authentication_without_expiration(const char *username, return; }
- ret = sysdb_cache_auth(test_ctx->sysdb, data->username, - (const uint8_t *)password, strlen(password), + ret = sysdb_cache_auth(test_ctx->sysdb, data->username, password, test_ctx->confdb, false, &expire_date, &delayed_until);
fail_unless(ret == expected_result, "sysdb_cache_auth request does not " @@ -1636,8 +1635,7 @@ static void cached_authentication_with_expiration(const char *username, data->attrs, SYSDB_MOD_REP); fail_unless(ret == EOK, "Could not modify user %s", data->username);
- ret = sysdb_cache_auth(test_ctx->sysdb, data->username, - (const uint8_t *) password, strlen(password), + ret = sysdb_cache_auth(test_ctx->sysdb, data->username, password, test_ctx->confdb, false, &expire_date, &delayed_until);
fail_unless(ret == expected_result,
This is useful for wiping passwords, as it prevents the compiler from optimizing out a memset to zero before a free() --- src/util/util.c | 9 +++++++++ src/util/util.h | 9 +++++++++ 2 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/src/util/util.c b/src/util/util.c index ab980775a1e4c87b16d32220bccda6cb644e0756..f268fbcd564cd93a2e63097c595cf19b65eb6800 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -700,3 +700,12 @@ bool string_in_list(const char *string, char **list, bool case_sensitive)
return false; } + +void safezero(void *data, size_t size) +{ + volatile uint8_t *p = data; + + while (size--) { + *p++ = 0; + } +} diff --git a/src/util/util.h b/src/util/util.h index c15ca668392105447d073c40666953a0145d375a..1c5f3fc52292e251bf7b8ad4d5b03a9d8a0a3243 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -540,6 +540,15 @@ errno_t add_string_to_list(TALLOC_CTX *mem_ctx, const char *string,
bool string_in_list(const char *string, char **list, bool case_sensitive);
+/** + * @brief Safely zero a segment of memory, + * prevents the compiler from optimizing out + * + * @param data The address of buffer to wipe + * @param s Size of the buffer + */ +void safezero(void *data, size_t size); + /* from sss_tc_utf8.c */ char * sss_tc_utf8_str_tolower(TALLOC_CTX *mem_ctx, const char *s);
These functions allow handling of auth tokens in a completely opaque way, with clear semantics and accessor fucntions that guarantee consistency, proper access to data and error conditions. --- Makefile.am | 2 + src/util/authtok.c | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/util/authtok.h | 180 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 384 insertions(+), 0 deletions(-) create mode 100644 src/util/authtok.c create mode 100644 src/util/authtok.h
diff --git a/Makefile.am b/Makefile.am index 3145f4950992cca9e4727b3883c1507fc57b5611..da1c5e0df7be12c4aa5606d4cc6c6d026015c45a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -369,6 +369,7 @@ dist_noinst_HEADERS = \ src/util/mmap_cache.h \ src/util/atomic_io.h \ src/util/auth_utils.h \ + src/util/authtok.h \ src/monitor/monitor.h \ src/monitor/monitor_interfaces.h \ src/responder/common/responder.h \ @@ -507,6 +508,7 @@ libsss_util_la_SOURCES = \ src/util/sss_tc_utf8.c \ src/util/murmurhash3.c \ src/util/atomic_io.c \ + src/util/authtok.c \ src/util/sss_selinux.c \ src/util/domain_info_utils.c \ src/util/util_lock.c diff --git a/src/util/authtok.c b/src/util/authtok.c new file mode 100644 index 0000000000000000000000000000000000000000..684b076220f79e426cec0139cddb9c93add6b482 --- /dev/null +++ b/src/util/authtok.c @@ -0,0 +1,202 @@ +/* + SSSD - auth utils + + Copyright (C) Simo Sorce simo@redhat.com 2012 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses/. +*/ + +#include "authtok.h" + +enum sss_authtok_type sss_authtok_get_type(struct sss_auth_token *tok) +{ + return tok->type; +} + +size_t sss_authtok_get_size(struct sss_auth_token *tok) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_PASSWORD: + case SSS_AUTHTOK_TYPE_CCFILE: + return tok->length; + case SSS_AUTHTOK_TYPE_EMPTY: + return 0; + } + + return EINVAL; +} + +uint8_t *sss_authtok_get_data(struct sss_auth_token *tok) +{ + return tok->data; +} + +errno_t sss_authtok_get_password(struct sss_auth_token *tok, + const char **pwd, size_t *len) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_EMPTY: + return ENOENT; + case SSS_AUTHTOK_TYPE_PASSWORD: + *pwd = (const char *)tok->data; + if (len) { + *len = tok->length - 1; + } + return EOK; + case SSS_AUTHTOK_TYPE_CCFILE: + return EACCES; + } + + return EINVAL; +} + +errno_t sss_authtok_get_ccfile(struct sss_auth_token *tok, + const char **ccfile, size_t *len) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_EMPTY: + return ENOENT; + case SSS_AUTHTOK_TYPE_CCFILE: + *ccfile = (const char *)tok->data; + if (len) { + *len = tok->length - 1; + } + return EOK; + case SSS_AUTHTOK_TYPE_PASSWORD: + return EACCES; + } + + return EINVAL; +} + +static errno_t sss_authtok_set_string(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + enum sss_authtok_type type, + const char *context_name, + const char *str, size_t len) +{ + size_t size; + + if (len == 0) { + len = strlen(str); + } else { + while (len > 0 && str[len - 1] == '\0') len--; + } + + if (len == 0) { + /* we do not allow zero length typed tokens */ + return EINVAL; + } + + size = len + 1; + + tok->data = talloc_named(mem_ctx, size, context_name); + if (!tok->data) { + return ENOMEM; + } + memcpy(tok->data, str, len); + tok->data[len] = '\0'; + tok->type = type; + tok->length = size; + + return EOK; + +} + +void sss_authtok_set_empty(struct sss_auth_token *tok) +{ + switch (tok->type) { + case SSS_AUTHTOK_TYPE_EMPTY: + return; + case SSS_AUTHTOK_TYPE_PASSWORD: + safezero(tok->data, tok->length); + break; + case SSS_AUTHTOK_TYPE_CCFILE: + break; + } + + tok->type = SSS_AUTHTOK_TYPE_EMPTY; + talloc_zfree(tok->data); + tok->length = 0; +} + +errno_t sss_authtok_set_password(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *password, size_t len) +{ + sss_authtok_set_empty(tok); + + return sss_authtok_set_string(mem_ctx, tok, + SSS_AUTHTOK_TYPE_PASSWORD, + "password", password, len); +} + +errno_t sss_authtok_set_ccfile(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *ccfile, size_t len) +{ + sss_authtok_set_empty(tok); + + return sss_authtok_set_string(mem_ctx, tok, + SSS_AUTHTOK_TYPE_CCFILE, + "ccfile", ccfile, len); +} + +errno_t sss_authtok_set(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + enum sss_authtok_type type, + uint8_t *data, size_t len) +{ + switch (type) { + case SSS_AUTHTOK_TYPE_PASSWORD: + return sss_authtok_set_password(mem_ctx, tok, (const char *)data, len); + case SSS_AUTHTOK_TYPE_CCFILE: + return sss_authtok_set_ccfile(mem_ctx, tok, (const char *)data, len); + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + return EOK; + } + + return EINVAL; +} + +errno_t sss_authtok_copy(TALLOC_CTX *mem_ctx, + struct sss_auth_token *src, + struct sss_auth_token *dst) +{ + sss_authtok_set_empty(dst); + + if (src->type == SSS_AUTHTOK_TYPE_EMPTY) { + return EOK; + } + + dst->data = talloc_memdup(mem_ctx, src->data, src->length); + if (!dst->data) { + return ENOMEM; + } + dst->length = src->length; + dst->type = src->type; + + return EOK; +} + +void sss_authtok_wipe_password(struct sss_auth_token *tok) +{ + if (tok->type != SSS_AUTHTOK_TYPE_PASSWORD) { + return; + } + + safezero(tok->data, tok->length); +} + diff --git a/src/util/authtok.h b/src/util/authtok.h new file mode 100644 index 0000000000000000000000000000000000000000..21cfe4a1c85489f7456651042bdf8041d7c55f58 --- /dev/null +++ b/src/util/authtok.h @@ -0,0 +1,180 @@ +/* + SSSD - auth utils + + Copyright (C) Simo Sorce simo@redhat.com 2012 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses/. +*/ + +#ifndef __AUTHTOK_H__ +#define __AUTHTOK_H__ + +#include "util/util.h" +#include "sss_client/sss_cli.h" + +/* Auth token structure, + * please never use directly. + * Use sss_authtok_* accesor functions instead + */ +struct sss_auth_token { + enum sss_authtok_type type; + uint8_t *data; + size_t length; +}; + +/** + * @brief Returns the token type + * + * @param tok A pointer to an sss_auth_token + * + * @return A sss_authtok_type (empty, password, ...) + */ +enum sss_authtok_type sss_authtok_get_type(struct sss_auth_token *tok); + +/** + * @brief Returns the token size + * + * @param tok A pointer to an sss_auth_token + * + * @return The current size of the token payload + */ +size_t sss_authtok_get_size(struct sss_auth_token *tok); + +/** + * @brief Get the data buffer + * + * @param tok A pointer to an sss_auth_token + * + * @return A pointer to the token payload + */ +uint8_t *sss_authtok_get_data(struct sss_auth_token *tok); + +/** + * @brief Returns a const string if the auth token is of type + SSS_AUTHTOK_TYPE_PASSWORD, otherwise it returns an error + * + * @param tok A pointer to an sss_auth_token + * @param pwd A pointer to a const char *, that will point to a null + * terminated string + * @param len The length of the password string + * + * @return EOK on success + * ENOENT if the token is empty + * EACCESS if the token is not a password token + */ +errno_t sss_authtok_get_password(struct sss_auth_token *tok, + const char **pwd, size_t *len); + +/** + * @brief Set a password into a an auth token, replacing any previous data + * + * @param mem_ctx A memory context use to allocate the internal data + * @param tok A pointer to a sss_auth_token structure to change + * @param password A string + * @param len The length of the string or, if 0 is passed, + * then strlen(password) will be used internally. + * + * @return EOK on success + * ENOMEM on error + */ +errno_t sss_authtok_set_password(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *password, size_t len); + +/** + * @brief Returns a const string if the auth token is of type + SSS_AUTHTOK_TYPE_CCFILE, otherwise it returns an error + * + * @param tok A pointer to an sss_auth_token + * @param ccfile A pointer to a const char *, that will point to a null + * terminated string + * @param len The length of the string + * + * @return EOK on success + * ENOENT if the token is empty + * EACCESS if the token is not a password token + */ +errno_t sss_authtok_get_ccfile(struct sss_auth_token *tok, + const char **ccfile, size_t *len); + +/** + * @brief Set a cc file name into a an auth token, replacing any previous data + * + * @param mem_ctx A memory context use to allocate the internal data + * @param tok A pointer to a sss_auth_token structure to change + * @param ccfile A null terminated string + * @param len The length of the string + * + * @return EOK on success + * ENOMEM on error + */ +errno_t sss_authtok_set_ccfile(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + const char *ccfile, size_t len); + +/** + * @brief Resets an auth token to the empty status + * + * @param tok A pointer to a sss_auth_token structure to reset + * + * NOTE: This function uses safezero() on the payload if the type + * is SSS_AUTHTOK_TYPE_PASSWORD + */ +void sss_authtok_set_empty(struct sss_auth_token *tok); + +/** + * @brief Set an auth token by type, replacing any previous data + * + * @param mem_ctx A memory context use to allocate the internal data + * @param tok A pointer to a sss_auth_token structure to change + * @param type A valid authtok type + * @param ccfile A data pointer + * @param len The length of the data + * + * @return EOK on success + * ENOMEM or EINVAL on error + */ +errno_t sss_authtok_set(TALLOC_CTX *mem_ctx, + struct sss_auth_token *tok, + enum sss_authtok_type type, + uint8_t *data, size_t len); + +/** + * @brief Copy an auth token from source to destination + * + * @param mem_ctx The memory context to use for allocations on dst + * @param src The source auth token + * @param dst The destination auth token + * + * @return EOK on success + * ENOMEM on error + */ +errno_t sss_authtok_copy(TALLOC_CTX *mem_ctx, + struct sss_auth_token *src, + struct sss_auth_token *dst); + +/** + * @brief Uses safezero to wipe the password from memory if the + * authtoken contains a password, otherwise does nothing. + * + * @param tok A pointer to a sss_auth_token structure to change + * + * NOTE: This function should only be used in destructors or similar + * functions where freing the actual string is unsafe and where it can + * be guaranteed that the auth token will not be used anymore. + * Use sss_authtok_set_empty() in normal circumstances. + */ +void sss_authtok_wipe_password(struct sss_auth_token *tok); + +#endif /* __AUTHTOK_H__ */
Use the new authtok abstraction and interfaces throught the code. --- Makefile.am | 2 + src/db/sysdb_ops.c | 1 - src/providers/data_provider.h | 9 +- src/providers/dp_auth_util.c | 76 +++++++---- src/providers/dp_pam_data_util.c | 113 ++++++++------- src/providers/ipa/ipa_auth.c | 6 +- src/providers/krb5/krb5_auth.c | 58 +++----- src/providers/krb5/krb5_child.c | 148 ++++++++++---------- src/providers/krb5/krb5_child_handler.c | 59 +++++++-- .../krb5/krb5_delayed_online_authentication.c | 50 +++++--- src/providers/krb5/krb5_renew_tgt.c | 18 +-- src/providers/ldap/ldap_auth.c | 90 +++++------- src/providers/ldap/sdap_async.c | 4 +- src/providers/ldap/sdap_async.h | 7 +- src/providers/ldap/sdap_async_connection.c | 88 +++++++----- src/providers/proxy/proxy.h | 7 +- src/providers/proxy/proxy_auth.c | 14 +- src/providers/proxy/proxy_child.c | 51 ++++--- src/responder/pam/pam_LOCAL_domain.c | 52 +++----- src/responder/pam/pamsrv_cmd.c | 134 ++++++++++-------- src/tests/krb5_child-test.c | 13 +- 21 files changed, 530 insertions(+), 470 deletions(-)
diff --git a/Makefile.am b/Makefile.am index da1c5e0df7be12c4aa5606d4cc6c6d026015c45a..6021b07a9a5e16e9ac9fcd58e1ba0637704a60e7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1449,6 +1449,7 @@ krb5_child_SOURCES = \ src/util/user_info_msg.c \ src/util/sss_krb5.c \ src/util/atomic_io.c \ + src/util/authtok.c \ src/util/util.c \ src/util/signal.c \ src/sss_client/common.c @@ -1470,6 +1471,7 @@ ldap_child_SOURCES = \ src/providers/ldap/ldap_child.c \ src/util/sss_krb5.c \ src/util/atomic_io.c \ + src/util/authtok.c \ src/util/util.c \ src/util/signal.c ldap_child_CFLAGS = \ diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c index e213023e3f1f1342984b7b2464a23a4544df9010..c7a5372b99baa534d79e4fb65db7a420d11b5662 100644 --- a/src/db/sysdb_ops.c +++ b/src/db/sysdb_ops.c @@ -2697,7 +2697,6 @@ int sysdb_cache_auth(struct sysdb_ctx *sysdb, time_t expire_date = -1; time_t delayed_until = -1; int ret; - int i;
if (name == NULL || *name == '\0') { DEBUG(1, ("Missing user name.\n")); diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h index bb944509da9f1dc89216266cf62c57fb4127fd57..b370aa51dbe4015a26512a0f003defdb6851bf63 100644 --- a/src/providers/data_provider.h +++ b/src/providers/data_provider.h @@ -41,6 +41,7 @@ #include "sbus/sssd_dbus.h" #include "sbus/sbus_client.h" #include "sss_client/sss_cli.h" +#include "util/authtok.h"
#define DATA_PROVIDER_VERSION 0x0001 #define DATA_PROVIDER_PIPE "private/sbus-dp" @@ -162,18 +163,14 @@ struct response_data {
struct pam_data { int cmd; - uint32_t authtok_type; - uint32_t authtok_size; - uint32_t newauthtok_type; - uint32_t newauthtok_size; char *domain; char *user; char *service; char *tty; char *ruser; char *rhost; - uint8_t *authtok; - uint8_t *newauthtok; + struct sss_auth_token authtok; + struct sss_auth_token newauthtok; uint32_t cli_pid;
int pam_status; diff --git a/src/providers/dp_auth_util.c b/src/providers/dp_auth_util.c index 9a67564b78e558642f4116528d210251a0d9b5fd..54f0ee8ed6f1d537410a91f93e55316fc9b89886 100644 --- a/src/providers/dp_auth_util.c +++ b/src/providers/dp_auth_util.c @@ -24,30 +24,43 @@ bool dp_pack_pam_request(DBusMessage *msg, struct pam_data *pd) { dbus_bool_t db_ret; + const char *service; + const char *tty; + const char *ruser; + const char *rhost; + uint32_t authtok_type; + uint32_t authtok_length; + uint8_t *authtok_data; + uint32_t new_authtok_type; + uint32_t new_authtok_length; + uint8_t *new_authtok_data;
if (pd->user == NULL) return false; - if (pd->service == NULL) pd->service = talloc_strdup(pd, ""); - if (pd->tty == NULL) pd->tty = talloc_strdup(pd, ""); - if (pd->ruser == NULL) pd->ruser = talloc_strdup(pd, ""); - if (pd->rhost == NULL) pd->rhost = talloc_strdup(pd, ""); - + service = pd->service ? pd->service : ""; + tty = pd->tty ? pd->tty : ""; + ruser = pd->ruser ? pd->ruser : ""; + rhost = pd->rhost ? pd->rhost : ""; + authtok_type = (uint32_t)sss_authtok_get_type(&pd->authtok); + authtok_data = sss_authtok_get_data(&pd->authtok); + authtok_length = sss_authtok_get_size(&pd->authtok); + new_authtok_type = (uint32_t)sss_authtok_get_type(&pd->newauthtok); + new_authtok_data = sss_authtok_get_data(&pd->newauthtok); + new_authtok_length = sss_authtok_get_size(&pd->newauthtok);
db_ret = dbus_message_append_args(msg, DBUS_TYPE_INT32, &(pd->cmd), DBUS_TYPE_STRING, &(pd->user), DBUS_TYPE_STRING, &(pd->domain), - DBUS_TYPE_STRING, &(pd->service), - DBUS_TYPE_STRING, &(pd->tty), - DBUS_TYPE_STRING, &(pd->ruser), - DBUS_TYPE_STRING, &(pd->rhost), - DBUS_TYPE_UINT32, &(pd->authtok_type), + DBUS_TYPE_STRING, &service, + DBUS_TYPE_STRING, &tty, + DBUS_TYPE_STRING, &ruser, + DBUS_TYPE_STRING, &rhost, + DBUS_TYPE_UINT32, &authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd->authtok), - (pd->authtok_size), - DBUS_TYPE_UINT32, &(pd->newauthtok_type), + &authtok_data, authtok_length, + DBUS_TYPE_UINT32, &new_authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd->newauthtok), - pd->newauthtok_size, + &new_authtok_data, new_authtok_length, DBUS_TYPE_INT32, &(pd->priv), DBUS_TYPE_UINT32, &(pd->cli_pid), DBUS_TYPE_INVALID); @@ -61,6 +74,12 @@ bool dp_unpack_pam_request(DBusMessage *msg, TALLOC_CTX *mem_ctx, dbus_bool_t db_ret; int ret; struct pam_data pd; + uint32_t authtok_type; + uint32_t authtok_length; + uint8_t *authtok_data; + uint32_t new_authtok_type; + uint32_t new_authtok_length; + uint8_t *new_authtok_data;
memset(&pd, 0, sizeof(pd));
@@ -72,14 +91,12 @@ bool dp_unpack_pam_request(DBusMessage *msg, TALLOC_CTX *mem_ctx, DBUS_TYPE_STRING, &(pd.tty), DBUS_TYPE_STRING, &(pd.ruser), DBUS_TYPE_STRING, &(pd.rhost), - DBUS_TYPE_UINT32, &(pd.authtok_type), + DBUS_TYPE_UINT32, &authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd.authtok), - &(pd.authtok_size), - DBUS_TYPE_UINT32, &(pd.newauthtok_type), + &authtok_data, &authtok_length, + DBUS_TYPE_UINT32, &new_authtok_type, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd.newauthtok), - &(pd.newauthtok_size), + &new_authtok_data, &new_authtok_length, DBUS_TYPE_INT32, &(pd.priv), DBUS_TYPE_UINT32, &(pd.cli_pid), DBUS_TYPE_INVALID); @@ -95,14 +112,17 @@ bool dp_unpack_pam_request(DBusMessage *msg, TALLOC_CTX *mem_ctx, return false; }
- if (pd.authtok_size != 0 && pd.authtok != NULL) { - memset(pd.authtok, 0, pd.authtok_size); - pd.authtok_size = 0; + ret = sss_authtok_set(*new_pd, &((*new_pd)->authtok), authtok_type, + authtok_data, authtok_length); + if (ret) { + DEBUG(1, ("Failed to set auth token: %d [%s]\n", ret, strerror(ret))); + return false; } - - if (pd.newauthtok_size != 0 && pd.newauthtok != NULL) { - memset(pd.newauthtok, 0, pd.newauthtok_size); - pd.newauthtok_size = 0; + ret = sss_authtok_set(*new_pd, &((*new_pd)->newauthtok), new_authtok_type, + new_authtok_data, new_authtok_length); + if (ret) { + DEBUG(1, ("Failed to set auth token: %d [%s]\n", ret, strerror(ret))); + return false; }
return true; diff --git a/src/providers/dp_pam_data_util.c b/src/providers/dp_pam_data_util.c index 889c47f00bfb49effab982ed40454b5120b84bf6..64f0d69bd0e8ebc28df958c393b40afcb5e18c31 100644 --- a/src/providers/dp_pam_data_util.c +++ b/src/providers/dp_pam_data_util.c @@ -25,26 +25,6 @@ #include "providers/data_provider.h"
-#define PD_STR_COPY(el) do { \ - if (old_pd->el != NULL) { \ - pd->el = talloc_strdup(pd, old_pd->el); \ - if (pd->el == NULL) { \ - DEBUG(1, ("talloc_strdup failed.\n")); \ - goto failed; \ - } \ - } \ -} while(0) - -#define PD_MEM_COPY(el, size) do { \ - if (old_pd->el != NULL) { \ - pd->el = talloc_memdup(pd, old_pd->el, (size)); \ - if (pd->el == NULL) { \ - DEBUG(1, ("talloc_memdup failed.\n")); \ - goto failed; \ - } \ - } \ -} while(0) - #define PAM_SAFE_ITEM(item) item ? item : "not set"
static const char *pamcmd2str(int cmd) { @@ -72,17 +52,11 @@ int pam_data_destructor(void *ptr) { struct pam_data *pd = talloc_get_type(ptr, struct pam_data);
- if (pd->authtok_size != 0 && pd->authtok != NULL) { - memset(pd->authtok, 0, pd->authtok_size); - pd->authtok_size = 0; - } + /* make sure to wipe any password from memory before freeing */ + sss_authtok_wipe_password(&pd->authtok); + sss_authtok_wipe_password(&pd->newauthtok);
- if (pd->newauthtok_size != 0 && pd->newauthtok != NULL) { - memset(pd->newauthtok, 0, pd->newauthtok_size); - pd->newauthtok_size = 0; - } - - return EOK; + return 0; }
struct pam_data *create_pam_data(TALLOC_CTX *mem_ctx) @@ -100,41 +74,72 @@ struct pam_data *create_pam_data(TALLOC_CTX *mem_ctx) return pd; }
-errno_t copy_pam_data(TALLOC_CTX *mem_ctx, struct pam_data *old_pd, - struct pam_data **new_pd) +errno_t copy_pam_data(TALLOC_CTX *mem_ctx, struct pam_data *src, + struct pam_data **dst) { struct pam_data *pd = NULL; + errno_t ret;
pd = create_pam_data(mem_ctx); if (pd == NULL) { - DEBUG(1, ("create_pam_data failed.\n")); - return ENOMEM; + ret = ENOMEM; + goto failed; }
- pd->cmd = old_pd->cmd; - pd->authtok_type = old_pd->authtok_type; - pd->authtok_size = old_pd->authtok_size; - pd->newauthtok_type = old_pd->newauthtok_type; - pd->newauthtok_size = old_pd->newauthtok_size; - pd->priv = old_pd->priv; + pd->cmd = src->cmd; + pd->priv = src->priv;
- PD_STR_COPY(domain); - PD_STR_COPY(user); - PD_STR_COPY(service); - PD_STR_COPY(tty); - PD_STR_COPY(ruser); - PD_STR_COPY(rhost); - PD_MEM_COPY(authtok, old_pd->authtok_size); - PD_MEM_COPY(newauthtok, old_pd->newauthtok_size); - pd->cli_pid = old_pd->cli_pid; + pd->domain = talloc_strdup(pd, src->domain); + if (pd->domain == NULL && src->domain != NULL) { + ret = ENOMEM; + goto failed; + } + pd->user = talloc_strdup(pd, src->user); + if (pd->user == NULL && src->user != NULL) { + ret = ENOMEM; + goto failed; + } + pd->service = talloc_strdup(pd, src->service); + if (pd->service == NULL && src->service != NULL) { + ret = ENOMEM; + goto failed; + } + pd->tty = talloc_strdup(pd, src->tty); + if (pd->tty == NULL && src->tty != NULL) { + ret = ENOMEM; + goto failed; + } + pd->ruser = talloc_strdup(pd, src->ruser); + if (pd->ruser == NULL && src->ruser != NULL) { + ret = ENOMEM; + goto failed; + } + pd->rhost = talloc_strdup(pd, src->rhost); + if (pd->rhost == NULL && src->rhost != NULL) { + ret = ENOMEM; + goto failed; + } + + pd->cli_pid = src->cli_pid; + + ret = sss_authtok_copy(pd, &src->authtok, &pd->authtok); + if (ret) { + goto failed; + } + + ret = sss_authtok_copy(pd, &src->newauthtok, &pd->newauthtok); + if (ret) { + goto failed; + }
- *new_pd = pd; + *dst = pd;
return EOK;
failed: talloc_free(pd); - return ENOMEM; + DEBUG(1, ("copy_pam_data failed: (%d) %s.\n", ret, strerror(ret))); + return ret; }
void pam_print_data(int l, struct pam_data *pd) @@ -146,10 +151,8 @@ void pam_print_data(int l, struct pam_data *pd) DEBUG(l, ("tty: %s\n", PAM_SAFE_ITEM(pd->tty))); DEBUG(l, ("ruser: %s\n", PAM_SAFE_ITEM(pd->ruser))); DEBUG(l, ("rhost: %s\n", PAM_SAFE_ITEM(pd->rhost))); - DEBUG(l, ("authtok type: %d\n", pd->authtok_type)); - DEBUG(l, ("authtok size: %d\n", pd->authtok_size)); - DEBUG(l, ("newauthtok type: %d\n", pd->newauthtok_type)); - DEBUG(l, ("newauthtok size: %d\n", pd->newauthtok_size)); + DEBUG(l, ("authtok type: %d\n", sss_authtok_get_type(&pd->authtok))); + DEBUG(l, ("newauthtok type: %d\n", sss_authtok_get_type(&pd->newauthtok))); DEBUG(l, ("priv: %d\n", pd->priv)); DEBUG(l, ("cli_pid: %d\n", pd->cli_pid)); } diff --git a/src/providers/ipa/ipa_auth.c b/src/providers/ipa/ipa_auth.c index eb62f0295cc0dc36daad9d4147556d993c7f1509..ee15afa5c83c0c68d19e169649ae6958a1553bd1 100644 --- a/src/providers/ipa/ipa_auth.c +++ b/src/providers/ipa/ipa_auth.c @@ -332,7 +332,6 @@ static void ipa_migration_flag_connect_done(struct tevent_req *req) const char **attrs; struct ldb_message *user_msg; const char *dn; - struct dp_opt_blob password; int dp_err = DP_ERR_FATAL; int ret;
@@ -374,11 +373,8 @@ static void ipa_migration_flag_connect_done(struct tevent_req *req) goto done; }
- password.data = state->pd->authtok; - password.length = state->pd->authtok_size; - req = sdap_auth_send(state, state->ev, state->sh, NULL, NULL, dn, - "password", password); + &state->pd->authtok); if (req == NULL) { DEBUG(SSSDBG_OP_FAILURE, ("sdap_auth_send failed.\n")); goto done; diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c index 5ef6cfc28625c55d850b73dc8cc621f33da1bdce..fa22575f1ce6790745b0761c1fefe9d8f6b021ad 100644 --- a/src/providers/krb5/krb5_auth.c +++ b/src/providers/krb5/krb5_auth.c @@ -278,12 +278,12 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, struct pam_data *pd, uid_t uid, int *pam_status, int *dp_err) { - char *password = NULL; + const char *password = NULL; errno_t ret;
- password = talloc_strndup(state, pd->authtok, pd->authtok_size); - if (!password) { - DEBUG(0, ("Out of memory copying password\n")); + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + if (ret != EOK) { + DEBUG(0, ("Failed to get password [%d] %s\n", ret, strerror(ret))); *pam_status = PAM_SYSTEM_ERR; *dp_err = DP_ERR_OK; return; @@ -294,7 +294,7 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, DEBUG(1, ("Offline authentication failed\n")); *pam_status = cached_login_pam_status(ret); *dp_err = DP_ERR_OK; - goto done; + return; }
ret = add_user_to_delayed_online_authentication(krb5_ctx, pd, uid); @@ -304,12 +304,6 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, } *pam_status = PAM_AUTHINFO_UNAVAIL; *dp_err = DP_ERR_OFFLINE; - -done: - if (password) { - for (i = 0; password[i]; i++) password[i] = 0; - talloc_zfree(password); - } }
static errno_t krb5_auth_prepare_ccache_file(struct krb5child_req *kr, @@ -385,16 +379,9 @@ static errno_t krb5_auth_prepare_ccache_file(struct krb5child_req *kr,
static void krb5_auth_store_creds(struct sysdb_ctx *sysdb, struct pam_data *pd) { - TALLOC_CTX *tmp_ctx; - char *password = NULL; + const char *password = NULL; int ret = EOK;
- tmp_ctx = talloc_new(NULL); - if (!tmp_ctx) { - DEBUG(0, ("Out of memory when trying to store credentials\n")); - return; - } - switch(pd->cmd) { case SSS_CMD_RENEW: /* The authtok is set to the credential cache @@ -404,42 +391,35 @@ static void krb5_auth_store_creds(struct sysdb_ctx *sysdb, struct pam_data *pd) break; case SSS_PAM_AUTHENTICATE: case SSS_PAM_CHAUTHTOK_PRELIM: - password = talloc_size(tmp_ctx, pd->authtok_size + 1); - if (password != NULL) { - memcpy(password, pd->authtok, pd->authtok_size); - password[pd->authtok_size] = '\0'; - } + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); break; case SSS_PAM_CHAUTHTOK: - password = talloc_size(tmp_ctx, pd->newauthtok_size + 1); - if (password != NULL) { - memcpy(password, pd->newauthtok, pd->newauthtok_size); - password[pd->newauthtok_size] = '\0'; - } + ret = sss_authtok_get_password(&pd->newauthtok, &password, NULL); break; default: DEBUG(0, ("unsupported PAM command [%d].\n", pd->cmd)); }
+ if (ret != EOK) { + DEBUG(0, ("Failed to get password [%d] %s\n", ret, strerror(ret))); + /* password caching failures are not fatal errors */ + return; + } + if (password == NULL) { if (pd->cmd != SSS_CMD_RENEW) { DEBUG(0, ("password not available, offline auth may not work.\n")); /* password caching failures are not fatal errors */ } - talloc_zfree(tmp_ctx); return; }
- talloc_set_destructor((TALLOC_CTX *)password, password_destructor); - ret = sysdb_cache_password(sysdb, pd->user, password); if (ret) { DEBUG(2, ("Failed to cache password, offline auth may not work." " (%d)[%s]!?\n", ret, strerror(ret))); /* password caching failures are not fatal errors */ } - - talloc_zfree(tmp_ctx); }
/* krb5_auth request */ @@ -504,9 +484,17 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx, case SSS_PAM_AUTHENTICATE: case SSS_CMD_RENEW: case SSS_PAM_CHAUTHTOK: + if (sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { + DEBUG(1, ("Missing authtok for user [%s].\n", pd->user)); + state->pam_status = PAM_SYSTEM_ERR; + state->dp_err = DP_ERR_FATAL; + ret = EINVAL; + goto done; + } break; case SSS_PAM_CHAUTHTOK_PRELIM: - if (pd->priv == 1 && pd->authtok_size == 0) { + if (pd->priv == 1 && + sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { DEBUG(4, ("Password reset by root is not supported.\n")); state->pam_status = PAM_PERM_DENIED; state->dp_err = DP_ERR_OK; diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c index 66e22f4330642189370e420d0c15bce56ca537fa..d1a42d56f1cb7137f2e21b54f6959da2fec5f6d0 100644 --- a/src/providers/krb5/krb5_child.c +++ b/src/providers/krb5/krb5_child.c @@ -950,7 +950,7 @@ done: }
static krb5_error_code get_and_save_tgt(struct krb5_req *kr, - char *password) + const char *password) { krb5_error_code kerr = 0; int ret; @@ -971,7 +971,8 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr, DEBUG(SSSDBG_TRACE_FUNC, ("Attempting kinit for realm [%s]\n",realm_name)); kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - password, sss_krb5_prompter, kr, 0, + discard_const(password), + sss_krb5_prompter, kr, 0, NULL, kr->options); if (kerr != 0) { KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); @@ -1066,8 +1067,8 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) { int ret; krb5_error_code kerr = 0; - char *pass_str = NULL; - char *newpass_str = NULL; + const char *password = NULL; + const char *newpassword = NULL; int pam_status = PAM_SYSTEM_ERR; int result_code = -1; krb5_data result_code_string; @@ -1082,20 +1083,15 @@ static errno_t changepw_child(int fd, struct krb5_req *kr)
DEBUG(SSSDBG_TRACE_LIBS, ("Password change operation\n"));
- if (kr->pd->authtok_type != SSS_AUTHTOK_TYPE_PASSWORD) { + ret = sss_authtok_get_password(&kr->pd->authtok, &password, NULL); + if (ret != EOK) { + DEBUG(1, ("Failed to fetch current password [%d] %s.\n", + ret, strerror(ret))); pam_status = PAM_CRED_INSUFFICIENT; kerr = KRB5KRB_ERR_GENERIC; goto sendresponse; }
- pass_str = talloc_strndup(kr, (const char *) kr->pd->authtok, - kr->pd->authtok_size); - if (pass_str == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - kerr = KRB5KRB_ERR_GENERIC; - goto sendresponse; - } - if (kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) { /* We do not need a password expiration warning here. */ prompter = NULL; @@ -1112,7 +1108,8 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) DEBUG(SSSDBG_TRACE_FUNC, ("Attempting kinit for realm [%s]\n",realm_name)); kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - pass_str, prompter, kr, 0, + discard_const(password), + prompter, kr, 0, SSSD_KRB5_CHANGEPW_PRINCIPAL, chagepw_options); sss_krb5_get_init_creds_opt_free(kr->ctx, chagepw_options); @@ -1121,9 +1118,7 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) goto sendresponse; }
- memset(pass_str, 0, kr->pd->authtok_size); - talloc_zfree(pass_str); - memset(kr->pd->authtok, 0, kr->pd->authtok_size); + sss_authtok_set_empty(&kr->pd->authtok);
if (kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) { DEBUG(SSSDBG_TRACE_LIBS, @@ -1134,17 +1129,18 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) goto sendresponse; }
- newpass_str = talloc_strndup(kr, (const char *) kr->pd->newauthtok, - kr->pd->newauthtok_size); - if (newpass_str == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); + ret = sss_authtok_get_password(&kr->pd->newauthtok, &newpassword, NULL); + if (ret != EOK) { + DEBUG(1, ("Failed to fetch new password [%d] %s.\n", + ret, strerror(ret))); kerr = KRB5KRB_ERR_GENERIC; goto sendresponse; }
memset(&result_code_string, 0, sizeof(krb5_data)); memset(&result_string, 0, sizeof(krb5_data)); - kerr = krb5_change_password(kr->ctx, kr->creds, newpass_str, &result_code, + kerr = krb5_change_password(kr->ctx, kr->creds, + discard_const(newpassword), &result_code, &result_code_string, &result_string);
if (kerr == KRB5_KDC_UNREACH) { @@ -1200,10 +1196,9 @@ static errno_t changepw_child(int fd, struct krb5_req *kr)
krb5_free_cred_contents(kr->ctx, kr->creds);
- kerr = get_and_save_tgt(kr, newpass_str); - memset(newpass_str, 0, kr->pd->newauthtok_size); - talloc_zfree(newpass_str); - memset(kr->pd->newauthtok, 0, kr->pd->newauthtok_size); + kerr = get_and_save_tgt(kr, newpassword); + + sss_authtok_set_empty(&kr->pd->newauthtok);
pam_status = kerr_to_status(kerr);
@@ -1220,28 +1215,21 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) { int ret; krb5_error_code kerr = 0; - char *pass_str = NULL; + const char *password = NULL; int pam_status = PAM_SYSTEM_ERR; krb5_get_init_creds_opt *chagepw_options;
DEBUG(SSSDBG_TRACE_LIBS, ("Attempting to get a TGT\n"));
- if (kr->pd->authtok_type != SSS_AUTHTOK_TYPE_PASSWORD) { + ret = sss_authtok_get_password(&kr->pd->authtok, &password, NULL); + if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Unknown authtok type\n")); pam_status = PAM_CRED_INSUFFICIENT; kerr = KRB5KRB_ERR_GENERIC; goto sendresponse; }
- pass_str = talloc_strndup(kr, (const char *) kr->pd->authtok, - kr->pd->authtok_size); - if (pass_str == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - kerr = KRB5KRB_ERR_GENERIC; - goto sendresponse; - } - - kerr = get_and_save_tgt(kr, pass_str); + kerr = get_and_save_tgt(kr, password);
/* If the password is expired the KDC will always return KRB5KDC_ERR_KEY_EXP regardless if the supplied password is correct or @@ -1264,7 +1252,8 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) }
kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - pass_str, sss_krb5_prompter, kr, 0, + discard_const(password), + sss_krb5_prompter, kr, 0, SSSD_KRB5_CHANGEPW_PRINCIPAL, chagepw_options);
@@ -1276,9 +1265,7 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) } }
- memset(pass_str, 0, kr->pd->authtok_size); - talloc_zfree(pass_str); - memset(kr->pd->authtok, 0, kr->pd->authtok_size); + sss_authtok_set_empty(&kr->pd->authtok);
pam_status = kerr_to_status(kerr);
@@ -1333,25 +1320,20 @@ static errno_t renew_tgt_child(int fd, struct krb5_req *kr) int ret; int status = PAM_AUTHTOK_ERR; int kerr; - char *ccname; + const char *ccname; krb5_ccache ccache = NULL;
DEBUG(SSSDBG_TRACE_LIBS, ("Renewing a ticket\n"));
- if (kr->pd->authtok_type != SSS_AUTHTOK_TYPE_CCFILE) { - DEBUG(1, ("Unsupported authtok type for TGT renewal [%d].\n", - kr->pd->authtok_type)); + ret = sss_authtok_get_ccfile(&kr->pd->authtok, &ccname, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + ("Unsupported authtok type for TGT renewal [%d].\n", + sss_authtok_get_type(&kr->pd->authtok))); kerr = EINVAL; goto done; }
- ccname = talloc_strndup(kr, (char *) kr->pd->authtok, kr->pd->authtok_size); - if (ccname == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - kerr = ENOMEM; - goto done; - } - kerr = krb5_cc_resolve(kr->ctx, ccname, &ccache); if (kerr != 0) { KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); @@ -1444,6 +1426,38 @@ static errno_t create_empty_ccache(int fd, struct krb5_req *kr) return ret; }
+static errno_t unpack_authtok(TALLOC_CTX *mem_ctx, struct sss_auth_token *tok, + uint8_t *buf, size_t size, size_t *p) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + errno_t ret = EOK; + + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, buf + *p, size, p); + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_length, buf + *p, size, p); + if ((*p + auth_token_length) > size) { + return EINVAL; + } + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_set_password(mem_ctx, tok, (char *)(buf + *p), 0); + break; + case SSS_AUTHTOK_TYPE_CCFILE: + ret = sss_authtok_set_ccfile(mem_ctx, tok, (char *)(buf + *p), 0); + break; + default: + return EINVAL; + } + + if (ret == EOK) { + *p += auth_token_length; + } + return ret; +} + static errno_t unpack_buffer(uint8_t *buf, size_t size, struct pam_data *pd, struct krb5_req *kr, uint32_t *offline) { @@ -1451,6 +1465,7 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size, struct pam_data *pd, uint32_t len; uint32_t validate; uint32_t different_realm; + errno_t ret;
DEBUG(SSSDBG_TRACE_LIBS, ("total buffer size: [%d]\n", size));
@@ -1491,35 +1506,26 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size, struct pam_data *pd, if (kr->keytab == NULL) return ENOMEM; p += len;
- SAFEALIGN_COPY_UINT32_CHECK(&pd->authtok_type, buf + p, size, &p); - SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p); - if ((p + len) > size) return EINVAL; - pd->authtok = (uint8_t *)talloc_strndup(pd, (char *)(buf + p), len); - if (pd->authtok == NULL) return ENOMEM; - pd->authtok_size = len + 1; - p += len; + ret = unpack_authtok(pd, &pd->authtok, buf, size, &p); + if (ret) { + return ret; + }
DEBUG(SSSDBG_CONF_SETTINGS, ("ccname: [%s] keytab: [%s]\n", kr->ccname, kr->keytab)); } else { kr->ccname = NULL; kr->keytab = NULL; - pd->authtok = NULL; - pd->authtok_size = 0; + sss_authtok_set_empty(&pd->authtok); }
if (pd->cmd == SSS_PAM_CHAUTHTOK) { - SAFEALIGN_COPY_UINT32_CHECK(&pd->newauthtok_type, buf + p, size, &p); - SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p); - - if ((p + len) > size) return EINVAL; - pd->newauthtok = (uint8_t *)talloc_strndup(pd, (char *)(buf + p), len); - if (pd->newauthtok == NULL) return ENOMEM; - pd->newauthtok_size = len + 1; - p += len; + ret = unpack_authtok(pd, &pd->newauthtok, buf, size, &p); + if (ret) { + return ret; + } } else { - pd->newauthtok = NULL; - pd->newauthtok_size = 0; + sss_authtok_set_empty(&pd->newauthtok); }
if (pd->cmd == SSS_PAM_ACCT_MGMT) { diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c index e792db3f7a6ebe7857b1ec699bc37d52ae3cad5d..5adbcf700ebf02a2aa524af3cecab51e543b4986 100644 --- a/src/providers/krb5/krb5_child_handler.c +++ b/src/providers/krb5/krb5_child_handler.c @@ -85,6 +85,43 @@ static int child_io_destructor(void *ptr) return EOK; }
+static errno_t pack_authtok(struct io_buffer *buf, size_t *rp, + struct sss_auth_token *tok) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + const char *data; + size_t len; + errno_t ret = EOK; + + auth_token_type = sss_authtok_get_type(tok); + + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + auth_token_length = 0; + data = ""; + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_get_password(tok, &data, &len); + auth_token_length = len + 1; + break; + case SSS_AUTHTOK_TYPE_CCFILE: + ret = sss_authtok_get_password(tok, &data, &len); + auth_token_length = len + 1; + break; + default: + ret = EINVAL; + } + + if (ret == EOK) { + SAFEALIGN_COPY_UINT32(&buf->data[*rp], &auth_token_type, rp); + SAFEALIGN_COPY_UINT32(&buf->data[*rp], &auth_token_length, rp); + safealign_memcpy(&buf->data[*rp], data, auth_token_length, rp); + } + + return ret; +} + static errno_t create_send_buffer(struct krb5child_req *kr, struct io_buffer **io_buf) { @@ -94,6 +131,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr, uint32_t validate; uint32_t different_realm; size_t username_len = 0; + errno_t ret;
keytab = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_KEYTAB); if (keytab == NULL) { @@ -117,11 +155,12 @@ static errno_t create_send_buffer(struct krb5child_req *kr, kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM || kr->pd->cmd == SSS_PAM_CHAUTHTOK) { buf->size += 4*sizeof(uint32_t) + strlen(kr->ccname) + strlen(keytab) + - kr->pd->authtok_size; + sss_authtok_get_size(&kr->pd->authtok); }
if (kr->pd->cmd == SSS_PAM_CHAUTHTOK) { - buf->size += 2*sizeof(uint32_t) + kr->pd->newauthtok_size; + buf->size += 2*sizeof(uint32_t) + + sss_authtok_get_size(&kr->pd->newauthtok); }
if (kr->pd->cmd == SSS_PAM_ACCT_MGMT) { @@ -157,17 +196,17 @@ static errno_t create_send_buffer(struct krb5child_req *kr, SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(keytab), &rp); safealign_memcpy(&buf->data[rp], keytab, strlen(keytab), &rp);
- SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->authtok_type, &rp); - SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->authtok_size, &rp); - safealign_memcpy(&buf->data[rp], kr->pd->authtok, - kr->pd->authtok_size, &rp); + ret = pack_authtok(buf, &rp, &kr->pd->authtok); + if (ret) { + return ret; + } }
if (kr->pd->cmd == SSS_PAM_CHAUTHTOK) { - SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->newauthtok_type, &rp); - SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->newauthtok_size, &rp); - safealign_memcpy(&buf->data[rp], kr->pd->newauthtok, - kr->pd->newauthtok_size, &rp); + ret = pack_authtok(buf, &rp, &kr->pd->newauthtok); + if (ret) { + return ret; + } }
if (kr->pd->cmd == SSS_PAM_ACCT_MGMT) { diff --git a/src/providers/krb5/krb5_delayed_online_authentication.c b/src/providers/krb5/krb5_delayed_online_authentication.c index d5dea3bb4c7661f45b6bea83cf803c7d681062cc..f95fa634c34ebee37bffb785abe4ef5b35318a82 100644 --- a/src/providers/krb5/krb5_delayed_online_authentication.c +++ b/src/providers/krb5/krb5_delayed_online_authentication.c @@ -71,27 +71,29 @@ static void authenticate_user(struct tevent_context *ev,
DEBUG_PAM_DATA(9, pd);
- if (pd->authtok == NULL || pd->authtok_size == 0) { - DEBUG(1, ("Missing authtok for user [%s].\n", pd->user)); - return; - } - #ifdef USE_KEYRING + char *password; long keysize; long keyrevoke; - int ret; - keysize = keyctl_read(pd->key_serial, (char *) pd->authtok, - pd->authtok_size); - keyrevoke = keyctl_revoke(pd->key_serial); + errno_t ret; + + keysize = keyctl_read_alloc(pd->key_serial, (void **)&password); if (keysize == -1) { ret = errno; DEBUG(1, ("keyctl_read failed [%d][%s].\n", ret, strerror(ret))); return; - } else if (keysize != pd->authtok_size) { - DEBUG(1, ("keyctl_read returned key with wrong size, " - "expect [%d] got [%d].\n", pd->authtok_size, keysize)); + } + + ret = sss_authtok_set_password(pd, &pd->authtok, password, keysize); + safezero(password, keysize); + free(password); + if (ret) { + DEBUG(1, ("failed to set password in auth token [%d][%s].\n", + ret, strerror(ret))); return; } + + keyrevoke = keyctl_revoke(pd->key_serial); if (keyrevoke == -1) { ret = errno; DEBUG(1, ("keyctl_revoke failed [%d][%s].\n", ret, strerror(ret))); @@ -244,8 +246,8 @@ errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx, return EINVAL; }
- if (pd->authtok_size == 0 || pd->authtok == NULL) { - DEBUG(1, ("Missing authtok for user [%s].\n", pd->user)); + if (sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { + DEBUG(1, ("Invalid authtok for user [%s].\n", pd->user)); return EINVAL; }
@@ -257,17 +259,29 @@ errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx,
#ifdef USE_KEYRING - new_pd->key_serial = add_key("user", new_pd->user, new_pd->authtok, - new_pd->authtok_size, KEY_SPEC_SESSION_KEYRING); + const char *password; + size_t len; + + ret = sss_authtok_get_password(&new_pd->authtok, &password, &len); + if (ret) { + DEBUG(1, ("Failed to get password [%d][%s].\n", ret, strerror(ret))); + sss_authtok_set_empty(&new_pd->authtok); + talloc_free(new_pd); + return ret; + } + + new_pd->key_serial = add_key("user", new_pd->user, password, len, + KEY_SPEC_SESSION_KEYRING); if (new_pd->key_serial == -1) { ret = errno; - DEBUG(1, ("add_key fialed [%d][%s].\n", ret, strerror(ret))); + DEBUG(1, ("add_key failed [%d][%s].\n", ret, strerror(ret))); + sss_authtok_set_empty(&new_pd->authtok); talloc_free(new_pd); return ret; } DEBUG(9, ("Saved authtok of user [%s] with serial [%ld].\n", new_pd->user, new_pd->key_serial)); - memset(new_pd->authtok, 0, new_pd->authtok_size); + sss_authtok_set_empty(&new_pd->authtok); #endif
key.type = HASH_KEY_ULONG; diff --git a/src/providers/krb5/krb5_renew_tgt.c b/src/providers/krb5/krb5_renew_tgt.c index ccb7e6af6d05121292d1152977c319daf660c9ef..4a812ab04d028961914557522423be82a1a01941 100644 --- a/src/providers/krb5/krb5_renew_tgt.c +++ b/src/providers/krb5/krb5_renew_tgt.c @@ -593,22 +593,14 @@ errno_t add_tgt_to_renew_table(struct krb5_ctx *krb5_ctx, const char *ccfile, goto done; }
- if (renew_data->pd->newauthtok_type != SSS_AUTHTOK_TYPE_EMPTY) { - talloc_zfree(renew_data->pd->newauthtok); - renew_data->pd->newauthtok_size = 0; - renew_data->pd->newauthtok_type = SSS_AUTHTOK_TYPE_EMPTY; - } + sss_authtok_set_empty(&renew_data->pd->newauthtok);
- talloc_zfree(renew_data->pd->authtok); - renew_data->pd->authtok = (uint8_t *) talloc_strdup(renew_data->pd, - renew_data->ccfile); - if (renew_data->pd->authtok == NULL) { - DEBUG(1, ("talloc_strdup failed.\n")); - ret = ENOMEM; + ret = sss_authtok_set_ccfile(renew_data->pd, &renew_data->pd->authtok, + renew_data->ccfile, 0); + if (ret) { + DEBUG(1, ("Failed to store ccfile in auth token.\n")); goto done; } - renew_data->pd->authtok_size = strlen((char *) renew_data->pd->authtok) + 1; - renew_data->pd->authtok_type = SSS_AUTHTOK_TYPE_CCFILE;
renew_data->pd->cmd = SSS_CMD_RENEW;
diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c index b78fdb8edefd785f140c94e62029a9a356e6d115..4025c0912cb8326e2c21f06d84ac40b65f39a7c9 100644 --- a/src/providers/ldap/ldap_auth.c +++ b/src/providers/ldap/ldap_auth.c @@ -463,7 +463,7 @@ struct auth_state { struct tevent_context *ev; struct sdap_auth_ctx *ctx; const char *username; - struct dp_opt_blob password; + struct sss_auth_token *authtok; struct sdap_service *sdap_service;
struct sdap_handle *sh; @@ -485,7 +485,7 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx, struct tevent_context *ev, struct sdap_auth_ctx *ctx, const char *username, - struct dp_opt_blob password, + struct sss_auth_token *authtok, bool try_chpass_service) { struct tevent_req *req; @@ -494,8 +494,8 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx, req = tevent_req_create(memctx, &state, struct auth_state); if (!req) return NULL;
- /* Treat a zero-length password as a failure */ - if (password.length == 0) { + /* The token must be a password token */ + if (sss_authtok_get_type(authtok) != SSS_AUTHTOK_TYPE_PASSWORD) { state->result = SDAP_AUTH_FAILED; tevent_req_done(req); return tevent_req_post(req, ev); @@ -504,7 +504,7 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx, state->ev = ev; state->ctx = ctx; state->username = username; - state->password = password; + state->authtok = authtok; state->srv = NULL; if (try_chpass_service && ctx->chpass_service != NULL && ctx->chpass_service->name != NULL) { @@ -633,7 +633,7 @@ static void auth_connect_done(struct tevent_req *subreq)
subreq = sdap_auth_send(state, state->ev, state->sh, NULL, NULL, state->dn, - "password", state->password); + state->authtok); if (!subreq) { tevent_req_error(req, ENOMEM); return; @@ -728,8 +728,6 @@ struct sdap_pam_chpass_state { struct pam_data *pd; const char *username; char *dn; - char *password; - char *new_password; struct sdap_handle *sh;
struct sdap_auth_ctx *ctx; @@ -745,7 +743,6 @@ void sdap_pam_chpass_handler(struct be_req *breq) struct sdap_auth_ctx *ctx; struct tevent_req *subreq; struct pam_data *pd; - struct dp_opt_blob authtok; int dp_err = DP_ERR_FATAL;
ctx = talloc_get_type(breq->be_ctx->bet_info[BET_CHPASS].pvt_bet_data, @@ -759,8 +756,8 @@ void sdap_pam_chpass_handler(struct be_req *breq) goto done; }
- if (pd->priv == 1 && pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM && - pd->authtok_size == 0) { + if ((pd->priv == 1) && (pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) && + (sss_authtok_get_type(&pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD)) { DEBUG(4, ("Password reset by root is not supported.\n")); pd->pam_status = PAM_PERM_DENIED; dp_err = DP_ERR_OK; @@ -783,25 +780,9 @@ void sdap_pam_chpass_handler(struct be_req *breq) state->pd = pd; state->username = pd->user; state->ctx = ctx; - state->password = talloc_strndup(state, - (char *)pd->authtok, pd->authtok_size); - if (!state->password) goto done; - talloc_set_destructor((TALLOC_CTX *)state->password, - password_destructor);
- if (pd->cmd == SSS_PAM_CHAUTHTOK) { - state->new_password = talloc_strndup(state, - (char *)pd->newauthtok, - pd->newauthtok_size); - if (!state->new_password) goto done; - talloc_set_destructor((TALLOC_CTX *)state->new_password, - password_destructor); - } - - authtok.data = (uint8_t *)state->password; - authtok.length = strlen(state->password); - subreq = auth_send(breq, breq->be_ctx->ev, - ctx, state->username, authtok, true); + subreq = auth_send(breq, breq->be_ctx->ev, ctx, + state->username, &pd->authtok, true); if (!subreq) goto done;
tevent_req_set_callback(subreq, sdap_auth4chpass_done, state); @@ -888,18 +869,30 @@ static void sdap_auth4chpass_done(struct tevent_req *req) state->pd->pam_status = PAM_MODULE_UNKNOWN; goto done; } else { + const char *password; + const char *new_password; + + ret = sss_authtok_get_password(&state->pd->authtok, + &password, NULL); + if (ret) { + state->pd->pam_status = PAM_SYSTEM_ERR; + goto done; + } + ret = sss_authtok_get_password(&state->pd->newauthtok, + &new_password, NULL); + if (ret) { + state->pd->pam_status = PAM_SYSTEM_ERR; + goto done; + } + subreq = sdap_exop_modify_passwd_send(state, state->breq->be_ctx->ev, - state->sh, - state->dn, - state->password, - state->new_password); - + state->sh, state->dn, + password, new_password); if (!subreq) { DEBUG(2, ("Failed to change password for %s\n", state->username)); goto done; } - tevent_req_set_callback(subreq, sdap_pam_chpass_done, state); return; } @@ -1014,8 +1007,6 @@ done: struct sdap_pam_auth_state { struct be_req *breq; struct pam_data *pd; - const char *username; - struct dp_opt_blob password; };
static void sdap_pam_auth_done(struct tevent_req *req); @@ -1050,12 +1041,9 @@ void sdap_pam_auth_handler(struct be_req *breq)
state->breq = breq; state->pd = pd; - state->username = pd->user; - state->password.data = pd->authtok; - state->password.length = pd->authtok_size;
subreq = auth_send(breq, breq->be_ctx->ev, ctx, - state->username, state->password, + pd->user, &pd->authtok, pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM ? true : false); if (!subreq) goto done;
@@ -1089,6 +1077,7 @@ static void sdap_pam_auth_done(struct tevent_req *req) enum pwexpire pw_expire_type; struct be_ctx *be_ctx = state->breq->be_ctx; void *pw_expire_data; + const char *password; int dp_err = DP_ERR_OK; int ret;
@@ -1171,26 +1160,19 @@ static void sdap_pam_auth_done(struct tevent_req *req) if (result == SDAP_AUTH_SUCCESS && state->breq->be_ctx->domain->cache_credentials) {
- char *password = talloc_strndup(state, (char *) - state->password.data, - state->password.length); - /* password caching failures are not fatal errors */ - if (!password) { - DEBUG(2, ("Failed to cache password for %s\n", state->username)); - goto done; + ret = sss_authtok_get_password(&state->pd->authtok, &password, NULL); + if (ret == EOK) { + ret = sysdb_cache_password(state->breq->be_ctx->sysdb, + state->pd->user, password); } - talloc_set_destructor((TALLOC_CTX *)password, password_destructor); - - ret = sysdb_cache_password(state->breq->be_ctx->sysdb, - state->username, password);
/* password caching failures are not fatal errors */ if (ret != EOK) { DEBUG(2, ("Failed to cache password for %s\n", - state->username)); + state->pd->user)); } else { DEBUG(4, ("Password successfully cached for %s\n", - state->username)); + state->pd->user)); } goto done; } diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c index e0440625d279fbbaa1cc2e6343b73f5a247371f7..84497b75ef586b58e27cc4dc9e6b8b3244464676 100644 --- a/src/providers/ldap/sdap_async.c +++ b/src/providers/ldap/sdap_async.c @@ -502,8 +502,8 @@ struct tevent_req *sdap_exop_modify_passwd_send(TALLOC_CTX *memctx, struct tevent_context *ev, struct sdap_handle *sh, char *user_dn, - char *password, - char *new_password) + const char *password, + const char *new_password) { struct tevent_req *req = NULL; struct sdap_exop_modify_passwd_state *state; diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h index 8c16d94e6486336e92b6112cd8b5a2dff4c97957..c5dc17037cd6d2c4ae88aa60d43d517eb2958085 100644 --- a/src/providers/ldap/sdap_async.h +++ b/src/providers/ldap/sdap_async.h @@ -108,8 +108,7 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, const char *sasl_mech, const char *sasl_user, const char *user_dn, - const char *authtok_type, - struct dp_opt_blob authtok); + struct sss_auth_token *authtok);
int sdap_auth_recv(struct tevent_req *req, TALLOC_CTX *memctx, @@ -128,8 +127,8 @@ struct tevent_req *sdap_exop_modify_passwd_send(TALLOC_CTX *memctx, struct tevent_context *ev, struct sdap_handle *sh, char *user_dn, - char *password, - char *new_password); + const char *password, + const char *new_password); int sdap_exop_modify_passwd_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, enum sdap_result *result, char **user_error_msg); diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c index ff99248433026608f06fc548824fa2dd25aaacaa..da50f4ad49ab4319b309cf6861f801014ac47102 100644 --- a/src/providers/ldap/sdap_async_connection.c +++ b/src/providers/ldap/sdap_async_connection.c @@ -493,7 +493,7 @@ static struct tevent_req *simple_bind_send(TALLOC_CTX *memctx, DEBUG(4, ("Executing simple bind as: %s\n", state->user_dn));
ret = ldap_sasl_bind(state->sh->ldap, state->user_dn, LDAP_SASL_SIMPLE, - state->pw, request_controls, NULL, &msgid); + pw, request_controls, NULL, &msgid); if (ctrls[0]) ldap_control_free(ctrls[0]); if (ret == -1 || msgid == -1) { ret = ldap_get_option(state->sh->ldap, @@ -1082,18 +1082,12 @@ int sdap_kinit_recv(struct tevent_req *req, /* ==Authenticaticate-User-by-DN========================================== */
struct sdap_auth_state { - const char *user_dn; - struct berval pw; struct sdap_ppolicy_data *ppolicy; - - int result; bool is_sasl; + int result; };
static void sdap_auth_done(struct tevent_req *subreq); -static int sdap_auth_get_authtok(const char *authtok_type, - struct dp_opt_blob authtok, - struct berval *pw);
/* TODO: handle sasl_cred */ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, @@ -1102,31 +1096,14 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, const char *sasl_mech, const char *sasl_user, const char *user_dn, - const char *authtok_type, - struct dp_opt_blob authtok) + struct sss_auth_token *authtok) { struct tevent_req *req, *subreq; struct sdap_auth_state *state; - int ret;
req = tevent_req_create(memctx, &state, struct sdap_auth_state); if (!req) return NULL;
- state->user_dn = user_dn; - - ret = sdap_auth_get_authtok(authtok_type, authtok, &state->pw); - if (ret != EOK) { - if (ret == ENOSYS) { - DEBUG(1, ("Getting authtok is not supported with the " - "crypto library compiled with, authentication " - "might fail!\n")); - } else { - DEBUG(1, ("Cannot parse authtok.\n")); - tevent_req_error(req, ret); - return tevent_req_post(req, ev); - } - } - if (sasl_mech) { state->is_sasl = true; subreq = sasl_bind_send(state, ev, sh, sasl_mech, sasl_user, NULL); @@ -1135,8 +1112,27 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, return tevent_req_post(req, ev); } } else { + const char *password = NULL; + struct berval pw; + size_t pwlen; + errno_t ret; + + ret = sss_authtok_get_password(authtok, &password, &pwlen); + if (ret != EOK) { + DEBUG(1, ("Cannot parse authtok.\n")); + tevent_req_error(req, ret); + return tevent_req_post(req, ev); + } + /* Treat a zero-length password as a failure */ + if (*password == '\0') { + tevent_req_error(req, ENOENT); + return tevent_req_post(req, ev); + } + pw.bv_val = discard_const(password); + pw.bv_len = pwlen - 1; + state->is_sasl = false; - subreq = simple_bind_send(state, ev, sh, user_dn, &state->pw); + subreq = simple_bind_send(state, ev, sh, user_dn, &pw); if (!subreq) { tevent_req_error(req, ENOMEM); return tevent_req_post(req, ev); @@ -1598,6 +1594,10 @@ static void sdap_cli_auth_step(struct tevent_req *req) SDAP_SASL_MECH); const char *user_dn = dp_opt_get_string(state->opts->basic, SDAP_DEFAULT_BIND_DN); + const char *authtok_type; + struct dp_opt_blob authtok_blob; + struct sss_auth_token authtok = { 0 }; + errno_t ret;
/* Set the LDAP expiration time * If SASL has already set it, use the sooner of the two @@ -1620,17 +1620,31 @@ static void sdap_cli_auth_step(struct tevent_req *req) return; }
- subreq = sdap_auth_send(state, - state->ev, - state->sh, - sasl_mech, + authtok_type = dp_opt_get_string(state->opts->basic, + SDAP_DEFAULT_AUTHTOK_TYPE); + if (authtok_type != NULL) { + if (strcasecmp(authtok_type, "password") != 0) { + DEBUG(SSSDBG_TRACE_LIBS, ("Invalid authtoken type\n")); + tevent_req_error(req, EINVAL); + return; + } + authtok_blob = dp_opt_get_blob(state->opts->basic, + SDAP_DEFAULT_AUTHTOK); + + ret = sss_authtok_set_password(state, &authtok, + (const char *)authtok_blob.data, + authtok_blob.length); + if (ret) { + tevent_req_error(req, ret); + return; + } + } + + subreq = sdap_auth_send(state, state->ev, + state->sh, sasl_mech, dp_opt_get_string(state->opts->basic, - SDAP_SASL_AUTHID), - user_dn, - dp_opt_get_string(state->opts->basic, - SDAP_DEFAULT_AUTHTOK_TYPE), - dp_opt_get_blob(state->opts->basic, - SDAP_DEFAULT_AUTHTOK)); + SDAP_SASL_AUTHID), + user_dn, &authtok); if (!subreq) { tevent_req_error(req, ENOMEM); return; diff --git a/src/providers/proxy/proxy.h b/src/providers/proxy/proxy.h index cea03382517231cdf2b96069ab93dfb7967b46a6..962cb28fc7d6362c45d268f289ffbce103a6e738 100644 --- a/src/providers/proxy/proxy.h +++ b/src/providers/proxy/proxy.h @@ -89,11 +89,8 @@ struct proxy_nss_ops { };
struct authtok_conv { - uint32_t authtok_size; - uint8_t *authtok; - - uint32_t newauthtok_size; - uint8_t *newauthtok; + struct sss_auth_token authtok; + struct sss_auth_token newauthtok;
bool sent_old; }; diff --git a/src/providers/proxy/proxy_auth.c b/src/providers/proxy/proxy_auth.c index 8088283fa8147f75b7d8eb4c83c63208163c9375..3430f38b282eff2da24735f8d635a952edde8888 100644 --- a/src/providers/proxy/proxy_auth.c +++ b/src/providers/proxy/proxy_auth.c @@ -712,7 +712,7 @@ static void proxy_child_done(struct tevent_req *req) struct proxy_client_ctx *client_ctx = tevent_req_callback_data(req, struct proxy_client_ctx); struct pam_data *pd = NULL; - char *password; + const char *password; int ret; struct tevent_immediate *imm;
@@ -747,17 +747,15 @@ static void proxy_child_done(struct tevent_req *req)
/* Check if we need to save the cached credentials */ if ((pd->cmd == SSS_PAM_AUTHENTICATE || pd->cmd == SSS_PAM_CHAUTHTOK) && - pd->pam_status == PAM_SUCCESS && - client_ctx->be_req->be_ctx->domain->cache_credentials) { - password = talloc_strndup(client_ctx->be_req, - (char *) pd->authtok, - pd->authtok_size); - if (!password) { + (pd->pam_status == PAM_SUCCESS) && + client_ctx->be_req->be_ctx->domain->cache_credentials) { + + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + if (ret) { /* password caching failures are not fatal errors */ DEBUG(2, ("Failed to cache password\n")); goto done; } - talloc_set_destructor((TALLOC_CTX *)password, password_destructor);
ret = sysdb_cache_password(client_ctx->be_req->be_ctx->sysdb, pd->user, password); diff --git a/src/providers/proxy/proxy_child.c b/src/providers/proxy/proxy_child.c index c575948a7036d9b73d93bd00e111834b12d28e7d..556dbf9b5488d75f0fa60386958f61b95d61fba2 100644 --- a/src/providers/proxy/proxy_child.c +++ b/src/providers/proxy/proxy_child.c @@ -80,6 +80,9 @@ static int proxy_internal_conv(int num_msg, const struct pam_message **msgm, int i; struct pam_response *reply; struct authtok_conv *auth_data; + const char *password; + size_t pwlen; + errno_t ret;
auth_data = talloc_get_type(appdata_ptr, struct authtok_conv);
@@ -94,11 +97,13 @@ static int proxy_internal_conv(int num_msg, const struct pam_message **msgm, case PAM_PROMPT_ECHO_OFF: DEBUG(4, ("Conversation message: [%s]\n", msgm[i]->msg)); reply[i].resp_retcode = 0; - reply[i].resp = calloc(auth_data->authtok_size + 1, - sizeof(char)); + + ret = sss_authtok_get_password(&auth_data->authtok, + &password, &pwlen); + if (ret) goto failed; + reply[i].resp = calloc(pwlen + 1, sizeof(char)); if (reply[i].resp == NULL) goto failed; - memcpy(reply[i].resp, auth_data->authtok, - auth_data->authtok_size); + memcpy(reply[i].resp, password, pwlen + 1);
break; default: @@ -124,6 +129,9 @@ static int proxy_chauthtok_conv(int num_msg, const struct pam_message **msgm, int i; struct pam_response *reply; struct authtok_conv *auth_data; + const char *password; + size_t pwlen; + errno_t ret;
auth_data = talloc_get_type(appdata_ptr, struct authtok_conv);
@@ -141,20 +149,23 @@ static int proxy_chauthtok_conv(int num_msg, const struct pam_message **msgm, reply[i].resp_retcode = 0; if (!auth_data->sent_old) { /* The first prompt will be asking for the old authtok */ - reply[i].resp = calloc(auth_data->authtok_size + 1, - sizeof(char)); + ret = sss_authtok_get_password(&auth_data->authtok, + &password, &pwlen); + if (ret) goto failed; + reply[i].resp = calloc(pwlen + 1, sizeof(char)); if (reply[i].resp == NULL) goto failed; - memcpy(reply[i].resp, auth_data->authtok, - auth_data->authtok_size); + memcpy(reply[i].resp, password, pwlen + 1); auth_data->sent_old = true; } else { /* Subsequent prompts are looking for the new authtok */ - reply[i].resp = calloc(auth_data->newauthtok_size + 1, - sizeof(char)); + ret = sss_authtok_get_password(&auth_data->newauthtok, + &password, &pwlen); + if (ret) goto failed; + reply[i].resp = calloc(pwlen + 1, sizeof(char)); if (reply[i].resp == NULL) goto failed; - memcpy(reply[i].resp, auth_data->newauthtok, - auth_data->newauthtok_size); + memcpy(reply[i].resp, password, pwlen + 1); + auth_data->sent_old = true; }
break; @@ -213,8 +224,8 @@ static errno_t call_pam_stack(const char *pam_target, struct pam_data *pd) } switch (pd->cmd) { case SSS_PAM_AUTHENTICATE: - auth_data->authtok_size = pd->authtok_size; - auth_data->authtok = pd->authtok; + sss_authtok_copy(auth_data, &pd->authtok, + &auth_data->authtok); pam_status = pam_authenticate(pamh, 0); break; case SSS_PAM_SETCRED: @@ -230,21 +241,21 @@ static errno_t call_pam_stack(const char *pam_target, struct pam_data *pd) pam_status=pam_close_session(pamh, 0); break; case SSS_PAM_CHAUTHTOK: - auth_data->authtok_size = pd->authtok_size; - auth_data->authtok = pd->authtok; + sss_authtok_copy(auth_data, &pd->authtok, + &auth_data->authtok); if (pd->priv != 1) { pam_status = pam_authenticate(pamh, 0); auth_data->sent_old = false; if (pam_status != PAM_SUCCESS) break; } - auth_data->newauthtok_size = pd->newauthtok_size; - auth_data->newauthtok = pd->newauthtok; + sss_authtok_copy(auth_data, &pd->newauthtok, + &auth_data->newauthtok); pam_status = pam_chauthtok(pamh, 0); break; case SSS_PAM_CHAUTHTOK_PRELIM: if (pd->priv != 1) { - auth_data->authtok_size = pd->authtok_size; - auth_data->authtok = pd->authtok; + sss_authtok_copy(auth_data, &pd->authtok, + &auth_data->authtok); pam_status = pam_authenticate(pamh, 0); } else { pam_status = PAM_SUCCESS; diff --git a/src/responder/pam/pam_LOCAL_domain.c b/src/responder/pam/pam_LOCAL_domain.c index 71446b4f8da53bfe4c0707621fafb228da5f808c..23eb7a2a8ddd3ae4480030633be867564b7f59f2 100644 --- a/src/responder/pam/pam_LOCAL_domain.c +++ b/src/responder/pam/pam_LOCAL_domain.c @@ -154,22 +154,19 @@ static void do_pam_acct_mgmt(struct LOCAL_request *lreq) static void do_pam_chauthtok(struct LOCAL_request *lreq) { int ret; - char *newauthtok; + const char *password; char *salt; char *new_hash; struct pam_data *pd;
pd = lreq->preq->pd;
- newauthtok = talloc_strndup(lreq, (char *) pd->newauthtok, - pd->newauthtok_size); - NULL_CHECK_OR_JUMP(newauthtok, ("talloc_strndup failed.\n"), lreq->error, - ENOMEM, done); - memset(pd->newauthtok, 0, pd->newauthtok_size); - - if (strlen(newauthtok) == 0) { + ret = sss_authtok_get_password(&pd->newauthtok, &password, NULL); + if (ret) { /* TODO: should we allow null passwords via a config option ? */ - DEBUG(1, ("Empty passwords are not allowed!\n")); + if (ret == ENOENT) { + DEBUG(1, ("Empty passwords are not allowed!\n")); + } lreq->error = EINVAL; goto done; } @@ -179,11 +176,10 @@ static void do_pam_chauthtok(struct LOCAL_request *lreq) lreq->error, ret, done); DEBUG(4, ("Using salt [%s]\n", salt));
- ret = s3crypt_sha512(lreq, newauthtok, salt, &new_hash); + ret = s3crypt_sha512(lreq, password, salt, &new_hash); NEQ_CHECK_OR_JUMP(ret, EOK, ("Hash generation failed.\n"), lreq->error, ret, done); DEBUG(4, ("New hash [%s]\n", new_hash)); - memset(newauthtok, 0, pd->newauthtok_size);
lreq->mod_attrs = sysdb_new_attrs(lreq); NULL_CHECK_OR_JUMP(lreq->mod_attrs, ("sysdb_new_attrs failed.\n"), @@ -204,7 +200,7 @@ static void do_pam_chauthtok(struct LOCAL_request *lreq) lreq->error, ret, done);
done: - return; + sss_authtok_set_empty(&pd->newauthtok); }
int LOCAL_pam_handler(struct pam_auth_req *preq) @@ -223,9 +219,9 @@ int LOCAL_pam_handler(struct pam_auth_req *preq) NULL}; struct ldb_result *res; const char *username = NULL; - const char *password = NULL; + const char *pwdhash = NULL; char *new_hash = NULL; - char *authtok = NULL; + const char *password; struct pam_data *pd = preq->pd; int ret;
@@ -287,25 +283,22 @@ int LOCAL_pam_handler(struct pam_auth_req *preq) DEBUG(4, ("allowing root to reset a password.\n")); break; } - authtok = talloc_strndup(lreq, (char *) pd->authtok, - pd->authtok_size); - NULL_CHECK_OR_JUMP(authtok, ("talloc_strndup failed.\n"), - lreq->error, ENOMEM, done); - memset(pd->authtok, 0, pd->authtok_size); + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + NEQ_CHECK_OR_JUMP(ret, EOK, ("Failed to get password.\n"), + lreq->error, ret, done);
- password = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_PWD, NULL); - NULL_CHECK_OR_JUMP(password, ("No password stored.\n"), + pwdhash = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_PWD, NULL); + NULL_CHECK_OR_JUMP(pwdhash, ("No password stored.\n"), lreq->error, LDB_ERR_NO_SUCH_ATTRIBUTE, done); - DEBUG(4, ("user: [%s], password hash: [%s]\n", username, password)); + DEBUG(4, ("user: [%s], password hash: [%s]\n", username, pwdhash));
- ret = s3crypt_sha512(lreq, authtok, password, &new_hash); - memset(authtok, 0, pd->authtok_size); + ret = s3crypt_sha512(lreq, password, pwdhash, &new_hash); NEQ_CHECK_OR_JUMP(ret, EOK, ("nss_sha512_crypt failed.\n"), lreq->error, ret, done);
DEBUG(4, ("user: [%s], new hash: [%s]\n", username, new_hash));
- if (strcmp(new_hash, password) != 0) { + if (strcmp(new_hash, pwdhash) != 0) { DEBUG(1, ("Passwords do not match.\n")); do_failed_login(lreq); goto done; @@ -338,13 +331,8 @@ int LOCAL_pam_handler(struct pam_auth_req *preq) }
done: - if (pd->authtok != NULL) - memset(pd->authtok, 0, pd->authtok_size); - if (authtok != NULL) - memset(authtok, 0, pd->authtok_size); - if (pd->newauthtok != NULL) - memset(pd->newauthtok, 0, pd->newauthtok_size); - + sss_authtok_set_empty(&pd->newauthtok); + sss_authtok_set_empty(&pd->authtok); prepare_reply(lreq); return EOK; } diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index ed7438f8d1509568bcd12bbbe7ab73984780bcdd..813894d39767248f74addac8596890ba7213a352 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -49,21 +49,38 @@ enum pam_verbosity {
static void pam_reply(struct pam_auth_req *preq);
-static int extract_authtok(uint32_t *type, uint32_t *size, uint8_t **tok, - size_t data_size, uint8_t *body, size_t blen, - size_t *c) { +static int extract_authtok_v2(TALLOC_CTX *mem_ctx, struct sss_auth_token *tok, + size_t data_size, uint8_t *body, size_t blen, + size_t *c) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + uint8_t *auth_token_data; + int ret = EOK;
if (data_size < sizeof(uint32_t) || *c+data_size > blen || SIZE_T_OVERFLOW(*c, data_size)) return EINVAL; - *size = data_size - sizeof(uint32_t);
- SAFEALIGN_COPY_UINT32_CHECK(type, &body[*c], blen, c); + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, &body[*c], blen, c); + auth_token_length = data_size - sizeof(uint32_t); + auth_token_data = body+(*c);
- *tok = body+(*c); + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_set_password(mem_ctx, tok, + (const char *)auth_token_data, + auth_token_length); + break; + default: + return EINVAL; + }
- *c += (*size); + *c += auth_token_length;
- return EOK; + return ret; }
static int extract_string(char **var, size_t size, uint8_t *body, size_t blen, @@ -185,14 +202,13 @@ static int pam_parse_in_data_v2(struct sss_domain_info *domains, if (ret != EOK) return ret; break; case SSS_PAM_ITEM_AUTHTOK: - ret = extract_authtok(&pd->authtok_type, &pd->authtok_size, - &pd->authtok, size, body, blen, &c); + ret = extract_authtok_v2(pd, &pd->authtok, + size, body, blen, &c); if (ret != EOK) return ret; break; case SSS_PAM_ITEM_NEWAUTHTOK: - ret = extract_authtok(&pd->newauthtok_type, - &pd->newauthtok_size, - &pd->newauthtok, size, body, blen, &c); + ret = extract_authtok_v2(pd, &pd->newauthtok, + size, body, blen, &c); if (ret != EOK) return ret; break; default: @@ -232,14 +248,44 @@ static int pam_parse_in_data_v3(struct sss_domain_info *domains, return EOK; }
+static int extract_authtok_v1(TALLOC_CTX *mem_ctx, struct sss_auth_token *tok, + uint8_t *body, size_t blen, size_t *c) +{ + uint32_t auth_token_type; + uint32_t auth_token_length; + uint8_t *auth_token_data; + int ret = EOK; + + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, &body[*c], blen, c); + SAFEALIGN_COPY_UINT32_CHECK(&auth_token_length, &body[*c], blen, c); + auth_token_data = body+(*c); + + switch (auth_token_type) { + case SSS_AUTHTOK_TYPE_EMPTY: + sss_authtok_set_empty(tok); + break; + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_set_password(mem_ctx, tok, + (const char *)auth_token_data, + auth_token_length); + break; + default: + return EINVAL; + } + + *c += auth_token_length; + + return ret; +} + static int pam_parse_in_data(struct sss_domain_info *domains, const char *default_domain, struct pam_data *pd, uint8_t *body, size_t blen) { - int start; - int end; - int last; + size_t start; + size_t end; + size_t last; int ret;
last = blen - 1; @@ -269,45 +315,15 @@ static int pam_parse_in_data(struct sss_domain_info *domains, if (body[end++] != '\0') return EINVAL; pd->rhost = (char *) &body[start];
- start = end; - pd->authtok_type = (int) body[start]; - - start += sizeof(uint32_t); - pd->authtok_size = (int) body[start]; - if (pd->authtok_size >= blen) return EINVAL; - - start += sizeof(uint32_t); - end = start + pd->authtok_size; - if (pd->authtok_size == 0) { - pd->authtok = NULL; - } else { - if (end <= blen) { - pd->authtok = (uint8_t *) &body[start]; - } else { - DEBUG(1, ("Invalid authtok size: %d\n", pd->authtok_size)); - return EINVAL; - } + ret = extract_authtok_v1(pd, &pd->authtok, body, blen, &end); + if (ret) { + DEBUG(1, ("Invalid auth token\n")); + return ret; } - - start = end; - pd->newauthtok_type = (int) body[start]; - - start += sizeof(uint32_t); - pd->newauthtok_size = (int) body[start]; - if (pd->newauthtok_size >= blen) return EINVAL; - - start += sizeof(uint32_t); - end = start + pd->newauthtok_size; - - if (pd->newauthtok_size == 0) { - pd->newauthtok = NULL; - } else { - if (end <= blen) { - pd->newauthtok = (uint8_t *) &body[start]; - } else { - DEBUG(1, ("Invalid newauthtok size: %d\n", pd->newauthtok_size)); - return EINVAL; - } + ret = extract_authtok_v1(pd, &pd->newauthtok, body, blen, &end); + if (ret) { + DEBUG(1, ("Invalid new auth token\n")); + return ret; }
DEBUG_PAM_DATA(4, pd); @@ -763,9 +779,9 @@ static void pam_reply(struct pam_auth_req *preq) goto done; }
- password = talloc_strndup(preq, pd->authtok, pd->authtok_size); - if (!password) { - DEBUG(0, ("Fatal: Out of memory copying password\n")); + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + if (ret) { + DEBUG(0, ("Failed to get password.\n")); goto done; }
@@ -775,10 +791,6 @@ static void pam_reply(struct pam_auth_req *preq) &exp_date, &delay_until);
pam_handle_cached_login(preq, ret, exp_date, delay_until); - if (password) { - for (i = 0; password[i]; i++) password[i] = 0; - talloc_zfree(password); - } return; } break; diff --git a/src/tests/krb5_child-test.c b/src/tests/krb5_child-test.c index 34d025b77b27a27e6131c1895c6c02644f921e5d..a72a3519985292456db6b9bbf9bccdcf678068a6 100644 --- a/src/tests/krb5_child-test.c +++ b/src/tests/krb5_child-test.c @@ -167,6 +167,9 @@ create_dummy_pam_data(TALLOC_CTX *mem_ctx, const char *user, const char *password) { struct pam_data *pd; + const char *authtok; + size_t authtok_len; + errno_t ret;
pd = talloc_zero(mem_ctx, struct pam_data); if (!pd) goto fail; @@ -175,12 +178,12 @@ create_dummy_pam_data(TALLOC_CTX *mem_ctx, const char *user, pd->user = talloc_strdup(pd, user); if (!pd->user) goto fail;
- pd->authtok = discard_const(talloc_strdup(pd, password)); - if (!pd->authtok) goto fail; - pd->authtok_size = strlen(password); - pd->authtok_type = SSS_AUTHTOK_TYPE_PASSWORD; + ret = sss_authtok_set_password(pd, &pd->authtok, password, 0); + if (ret) goto fail; + + (void)sss_authtok_get_password(&pd->authtok, &authtok, &authtok_len); DEBUG(SSSDBG_FUNC_DATA, ("Authtok [%s] len [%d]\n", - pd->authtok, pd->authtok_size)); + authtok, (int)authtok_len));
return pd;
On 12/04/2012 02:30 PM, Simo Sorce wrote:
Fixed switch/case-return errors. The rest is the same.
Simo Sorce (4): Code can only check for cached passwords Add function to safely wipe memory. Add authtok utility functions. Change pam data auth tokens.
Makefile.am | 4 + src/db/sysdb.h | 3 +- src/db/sysdb_ops.c | 13 +-- src/providers/data_provider.h | 9 +- src/providers/dp_auth_util.c | 76 +++++--- src/providers/dp_pam_data_util.c | 113 ++++++------ src/providers/ipa/ipa_auth.c | 6 +- src/providers/krb5/krb5_auth.c | 55 +++--- src/providers/krb5/krb5_child.c | 148 ++++++++------- src/providers/krb5/krb5_child_handler.c | 59 +++++- .../krb5/krb5_delayed_online_authentication.c | 50 +++-- src/providers/krb5/krb5_renew_tgt.c | 18 +-- src/providers/ldap/ldap_auth.c | 90 ++++------ src/providers/ldap/sdap_async.c | 4 +- src/providers/ldap/sdap_async.h | 7 +- src/providers/ldap/sdap_async_connection.c | 88 +++++---- src/providers/proxy/proxy.h | 7 +- src/providers/proxy/proxy_auth.c | 14 +- src/providers/proxy/proxy_child.c | 51 +++-- src/responder/pam/pam_LOCAL_domain.c | 52 ++--- src/responder/pam/pamsrv_cmd.c | 159 +++++++++------- src/tests/krb5_child-test.c | 13 +- src/tests/sysdb-tests.c | 6 +- src/util/authtok.c | 202 ++++++++++++++++++++ src/util/authtok.h | 180 +++++++++++++++++ src/util/util.c | 9 + src/util/util.h | 9 + 27 files changed, 958 insertions(+), 487 deletions(-) create mode 100644 src/util/authtok.c create mode 100644 src/util/authtok.h
sssd-devel mailing list sssd-devel@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/sssd-devel
Hi, I'm sorry, I still wasn't able to get through the whole 4th patch. It is really hard to keep track of those changes in 2000 line patch. Is it possible to split it somehow?
Also I noticed that you used numbers instead of macro to specify debug level many times. Can you please switch to macros?
Thanks.
On Thu, 2013-01-03 at 11:03 +0100, Pavel Březina wrote:
On 12/04/2012 02:30 PM, Simo Sorce wrote:
Fixed switch/case-return errors. The rest is the same.
Simo Sorce (4): Code can only check for cached passwords Add function to safely wipe memory. Add authtok utility functions. Change pam data auth tokens.
Makefile.am | 4 + src/db/sysdb.h | 3 +- src/db/sysdb_ops.c | 13 +-- src/providers/data_provider.h | 9 +- src/providers/dp_auth_util.c | 76 +++++--- src/providers/dp_pam_data_util.c | 113 ++++++------ src/providers/ipa/ipa_auth.c | 6 +- src/providers/krb5/krb5_auth.c | 55 +++--- src/providers/krb5/krb5_child.c | 148 ++++++++------- src/providers/krb5/krb5_child_handler.c | 59 +++++- .../krb5/krb5_delayed_online_authentication.c | 50 +++-- src/providers/krb5/krb5_renew_tgt.c | 18 +-- src/providers/ldap/ldap_auth.c | 90 ++++------ src/providers/ldap/sdap_async.c | 4 +- src/providers/ldap/sdap_async.h | 7 +- src/providers/ldap/sdap_async_connection.c | 88 +++++---- src/providers/proxy/proxy.h | 7 +- src/providers/proxy/proxy_auth.c | 14 +- src/providers/proxy/proxy_child.c | 51 +++-- src/responder/pam/pam_LOCAL_domain.c | 52 ++--- src/responder/pam/pamsrv_cmd.c | 159 +++++++++------- src/tests/krb5_child-test.c | 13 +- src/tests/sysdb-tests.c | 6 +- src/util/authtok.c | 202 ++++++++++++++++++++ src/util/authtok.h | 180 +++++++++++++++++ src/util/util.c | 9 + src/util/util.h | 9 + 27 files changed, 958 insertions(+), 487 deletions(-) create mode 100644 src/util/authtok.c create mode 100644 src/util/authtok.h
sssd-devel mailing list sssd-devel@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/sssd-devel
Hi, I'm sorry, I still wasn't able to get through the whole 4th patch. It is really hard to keep track of those changes in 2000 line patch. Is it possible to split it somehow?
It would fail to compile. But the 4th patch should just be tedious mechanical changes, is there something specific that distracts you ? Maybe you can simply review a few files at a time ?
Also I noticed that you used numbers instead of macro to specify debug level many times. Can you please switch to macros?
I didn't want to change anything I did not need to because the patch was already big. I am not adding new debugging IIRC, just changing authtok stuff, I thought changing debugging would just make the code more burdensome to review.
Simo.
On 12/04/2012 02:30 PM, Simo Sorce wrote:
Fixed switch/case-return errors. The rest is the same.
Simo Sorce (4): Code can only check for cached passwords Add function to safely wipe memory. Add authtok utility functions. Change pam data auth tokens.
Makefile.am | 4 + src/db/sysdb.h | 3 +- src/db/sysdb_ops.c | 13 +-- src/providers/data_provider.h | 9 +- src/providers/dp_auth_util.c | 76 +++++--- src/providers/dp_pam_data_util.c | 113 ++++++------ src/providers/ipa/ipa_auth.c | 6 +- src/providers/krb5/krb5_auth.c | 55 +++--- src/providers/krb5/krb5_child.c | 148 ++++++++------- src/providers/krb5/krb5_child_handler.c | 59 +++++- .../krb5/krb5_delayed_online_authentication.c | 50 +++-- src/providers/krb5/krb5_renew_tgt.c | 18 +-- src/providers/ldap/ldap_auth.c | 90 ++++------ src/providers/ldap/sdap_async.c | 4 +- src/providers/ldap/sdap_async.h | 7 +- src/providers/ldap/sdap_async_connection.c | 88 +++++---- src/providers/proxy/proxy.h | 7 +- src/providers/proxy/proxy_auth.c | 14 +- src/providers/proxy/proxy_child.c | 51 +++-- src/responder/pam/pam_LOCAL_domain.c | 52 ++--- src/responder/pam/pamsrv_cmd.c | 159 +++++++++------- src/tests/krb5_child-test.c | 13 +- src/tests/sysdb-tests.c | 6 +- src/util/authtok.c | 202 ++++++++++++++++++++ src/util/authtok.h | 180 +++++++++++++++++ src/util/util.c | 9 + src/util/util.h | 9 + 27 files changed, 958 insertions(+), 487 deletions(-) create mode 100644 src/util/authtok.c create mode 100644 src/util/authtok.h
sssd-devel mailing list sssd-devel@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/sssd-devel
Ack to all four.
On Thu, 2013-01-10 at 11:04 +0100, Pavel Březina wrote:
On 12/04/2012 02:30 PM, Simo Sorce wrote:
Fixed switch/case-return errors. The rest is the same.
Simo Sorce (4): Code can only check for cached passwords Add function to safely wipe memory. Add authtok utility functions. Change pam data auth tokens.
Makefile.am | 4 + src/db/sysdb.h | 3 +- src/db/sysdb_ops.c | 13 +-- src/providers/data_provider.h | 9 +- src/providers/dp_auth_util.c | 76 +++++--- src/providers/dp_pam_data_util.c | 113 ++++++------ src/providers/ipa/ipa_auth.c | 6 +- src/providers/krb5/krb5_auth.c | 55 +++--- src/providers/krb5/krb5_child.c | 148 ++++++++------- src/providers/krb5/krb5_child_handler.c | 59 +++++- .../krb5/krb5_delayed_online_authentication.c | 50 +++-- src/providers/krb5/krb5_renew_tgt.c | 18 +-- src/providers/ldap/ldap_auth.c | 90 ++++------ src/providers/ldap/sdap_async.c | 4 +- src/providers/ldap/sdap_async.h | 7 +- src/providers/ldap/sdap_async_connection.c | 88 +++++---- src/providers/proxy/proxy.h | 7 +- src/providers/proxy/proxy_auth.c | 14 +- src/providers/proxy/proxy_child.c | 51 +++-- src/responder/pam/pam_LOCAL_domain.c | 52 ++--- src/responder/pam/pamsrv_cmd.c | 159 +++++++++------- src/tests/krb5_child-test.c | 13 +- src/tests/sysdb-tests.c | 6 +- src/util/authtok.c | 202 ++++++++++++++++++++ src/util/authtok.h | 180 +++++++++++++++++ src/util/util.c | 9 + src/util/util.h | 9 + 27 files changed, 958 insertions(+), 487 deletions(-) create mode 100644 src/util/authtok.c create mode 100644 src/util/authtok.h
sssd-devel mailing list sssd-devel@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/sssd-devel
Ack to all four.
Thanks, pushed to master.
Simo.
sssd-devel@lists.fedorahosted.org