From 64af76e2bef2565caa9738f675c108a4b3789237 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Jan 10 2013 17:24:59 +0000 Subject: Change pam data auth tokens. Use the new authtok abstraction and interfaces throught the code. --- diff --git a/Makefile.am b/Makefile.am index 3eb8cc0..98d8bba 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1459,6 +1459,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 @@ -1480,6 +1481,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 b9cecad..9974beb 100644 --- a/src/db/sysdb_ops.c +++ b/src/db/sysdb_ops.c @@ -2780,7 +2780,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 f131e2c..8e475d2 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" @@ -169,18 +170,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 9a67564..54f0ee8 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 889c47f..64f0d69 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 = src->cmd; + pd->priv = src->priv; + + 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; } - 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_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; - - *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 eb62f02..ee15afa 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 bd014a4..398f06a 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 66e22f4..d1a42d5 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 e792db3..5adbcf7 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 d5dea3b..f95fa63 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 b5eee69..8531542 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 b0dd30c..3dcb0b2 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) { @@ -629,7 +629,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; @@ -721,8 +721,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; @@ -738,7 +736,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, @@ -752,8 +749,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; @@ -776,25 +773,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); @@ -881,18 +862,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; } @@ -1007,8 +1000,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); @@ -1043,12 +1034,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; @@ -1082,6 +1070,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; @@ -1164,26 +1153,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 e044062..84497b7 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 8c16d94..c5dc170 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 ff99248..da50f4a 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, - dp_opt_get_string(state->opts->basic, - SDAP_SASL_AUTHID), - user_dn, + 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_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 cea0338..962cb28 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 8088283..3430f38 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 c575948..556dbf9 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 71446b4..23eb7a2 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); - - password = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_PWD, NULL); - NULL_CHECK_OR_JUMP(password, ("No password stored.\n"), + ret = sss_authtok_get_password(&pd->authtok, &password, NULL); + NEQ_CHECK_OR_JUMP(ret, EOK, ("Failed to get password.\n"), + lreq->error, ret, done); + + 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 ed7438f..813894d 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 34d025b..a72a351 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;