[SSSD] [PATCH 4/4] Change pam data auth tokens.

Simo Sorce simo at redhat.com
Thu Nov 1 05:24:56 UTC 2012


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;
 
-- 
1.7.1




More information about the sssd-devel mailing list