| // Copyright (c) 2013 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // A helper which provides methods to extract data from a pam_handle. |
| |
| #include "chaps/pam_helper.h" |
| |
| #include <security/pam_appl.h> |
| #include <security/pam_modules.h> |
| |
| #include <vector> |
| |
| #include <base/logging.h> |
| #include <chromeos/secure_blob.h> |
| |
| #include "chaps/chaps_utility.h" |
| |
| using std::string; |
| using std::vector; |
| using chromeos::SecureBlob; |
| |
| namespace chaps { |
| |
| namespace { |
| |
| const char* kUserKey = "chaps_user_key"; |
| const char* kPasswordKey = "chaps_password_key"; |
| |
| static void FreeUser(pam_handle_t *pam_handle, void *data, |
| int error_status) { |
| if (data != NULL) { |
| string* user = reinterpret_cast<string*>(data); |
| delete user; |
| } |
| } |
| |
| static void FreePassword(pam_handle_t *pam_handle, void *data, |
| int error_status) { |
| if (data != NULL) { |
| SecureBlob* password = reinterpret_cast<SecureBlob*>(data); |
| password->clear(); |
| delete password; |
| } |
| } |
| |
| } // namespace |
| |
| PamHelper::~PamHelper() { } |
| |
| bool PamHelper::GetPamUser(pam_handle_t* pam_handle, string* user) { |
| const char* user_raw; |
| int result; |
| |
| result = pam_get_user(pam_handle, &user_raw, NULL); |
| if (result != PAM_SUCCESS) { |
| LOG(ERROR) << "Could not get the pam user name: " |
| << pam_strerror(pam_handle, result); |
| return false; |
| } |
| |
| *user = string(user_raw); |
| // Note: user_raw is the actual data, so should not be overwritten or freed. |
| return true; |
| } |
| |
| bool PamHelper::GetPamPassword(pam_handle_t* pam_handle, |
| bool old_password, |
| SecureBlob* data) { |
| const char* data_raw; |
| int result; |
| int pam_item_type; |
| |
| pam_item_type = old_password ? PAM_OLDAUTHTOK : PAM_AUTHTOK; |
| |
| result = pam_get_item(pam_handle, pam_item_type, |
| reinterpret_cast<const void **>(&data_raw)); |
| if (result != PAM_SUCCESS || data_raw == NULL) { |
| // TODO(rmcilroy): Prompt for password if possible. |
| LOG(WARNING) << "Could not get pam password: " |
| << pam_strerror(pam_handle, result); |
| return false; |
| } |
| |
| SecureBlob tmp(data_raw, strlen(data_raw)); |
| data->swap(tmp); |
| |
| // Note: data_raw is the actual data, so should not be overwritten or freed. |
| return true; |
| } |
| |
| bool PamHelper::SaveUserAndPassword(pam_handle_t* pam_handle, |
| const string& user, |
| const SecureBlob& password) { |
| void* user_data = new string(user); |
| if (pam_set_data(pam_handle, kUserKey, user_data, FreeUser) != PAM_SUCCESS) { |
| LOG(ERROR) << "Could not save user name in PAM handle"; |
| return false; |
| } |
| |
| void* password_data = new SecureBlob(password); |
| if (pam_set_data(pam_handle, kPasswordKey, password_data, FreePassword) != |
| PAM_SUCCESS) { |
| LOG(ERROR) << "Could not save password in PAM handle"; |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool PamHelper::RetrieveUserAndPassword(pam_handle_t* pam_handle, |
| string* user, |
| SecureBlob* password) { |
| CHECK(user); |
| CHECK(password); |
| |
| const void* user_data; |
| if (pam_get_data(pam_handle, kUserKey, &user_data) != PAM_SUCCESS) { |
| VLOG(1) << "Could not retrieve user name from PAM handle"; |
| return false; |
| } |
| *user = *reinterpret_cast<const string*>(user_data); |
| |
| const void* password_data; |
| if (pam_get_data(pam_handle, kPasswordKey, &password_data) != PAM_SUCCESS) { |
| LOG(INFO) << "Could not retrieve password from PAM handle"; |
| return false; |
| } |
| SecureBlob tmp(*reinterpret_cast<const SecureBlob*>(password_data)); |
| password->swap(tmp); |
| |
| return true; |
| } |
| |
| bool PamHelper::PutEnvironmentVariable(pam_handle_t* pam_handle, |
| const string& name, |
| const string& value) { |
| string env_var = name + "=" + value; |
| return pam_putenv(pam_handle, env_var.c_str()) == PAM_SUCCESS; |
| } |
| |
| bool PamHelper::GetEnvironmentVariable(pam_handle_t* pam_handle, |
| const string& name, |
| string* value) { |
| CHECK(value); |
| const char* value_raw = pam_getenv(pam_handle, name.c_str()); |
| if (value_raw == NULL || value_raw[0] == '\0') |
| return false; |
| *value = string(value_raw); |
| return true; |
| } |
| |
| } // namespace chaps |