getUserDB_unittest.cc (4783B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 #include "gtest/gtest.h" 7 #include "prenv.h" 8 #include "seccomon.h" 9 10 #include <stdlib.h> 11 #include <string> 12 #include <unistd.h> 13 #include <sys/stat.h> 14 15 namespace nss_test { 16 17 // Return the path to user's NSS database. 18 extern "C" char *getUserDB(void); 19 20 class Sysinit : public ::testing::Test { 21 protected: 22 void SetUp() { 23 home_var_ = PR_GetEnvSecure("HOME"); 24 if (home_var_) { 25 old_home_dir_ = home_var_; 26 } 27 xdg_data_home_var_ = PR_GetEnvSecure("XDG_DATA_HOME"); 28 if (xdg_data_home_var_) { 29 old_xdg_data_home_ = xdg_data_home_var_; 30 ASSERT_EQ(0, unsetenv("XDG_DATA_HOME")); 31 } 32 char tmp[] = "/tmp/nss-tmp.XXXXXX"; 33 tmp_home_ = mkdtemp(tmp); 34 ASSERT_EQ(0, setenv("HOME", tmp_home_.c_str(), 1)); 35 } 36 37 void TearDown() { 38 // Set HOME back to original 39 if (home_var_) { 40 ASSERT_EQ(0, setenv("HOME", old_home_dir_.c_str(), 1)); 41 } else { 42 ASSERT_EQ(0, unsetenv("HOME")); 43 } 44 // Set XDG_DATA_HOME back to original 45 if (xdg_data_home_var_) { 46 ASSERT_EQ(0, setenv("XDG_DATA_HOME", old_xdg_data_home_.c_str(), 1)); 47 } 48 // Remove test dirs. 49 if (!nssdir_.empty()) { 50 ASSERT_EQ(0, RemoveEmptyDirsFromStart(nssdir_, tmp_home_)); 51 } 52 } 53 54 // Remove all dirs within @start from @path containing only empty dirs. 55 // Assumes @start already exists. 56 // Upon successful completion, return 0. Otherwise, -1. 57 static int RemoveEmptyDirsFromStart(std::string path, std::string start) { 58 if (path.find(start) == std::string::npos) { 59 return -1; 60 } 61 std::string temp = path; 62 if (rmdir(temp.c_str())) { 63 return -1; 64 } 65 for (size_t i = temp.length() - 1; i > start.length(); --i) { 66 if (temp[i] == '/') { 67 temp[i] = '\0'; 68 if (rmdir(temp.c_str())) { 69 return -1; 70 } 71 } 72 } 73 if (rmdir(start.c_str())) { 74 return -1; 75 } 76 return 0; 77 } 78 79 // Create empty dirs appending @path to @start with mode @mode. 80 // Assumes @start already exists. 81 // Upon successful completion, return the string @start + @path. 82 static std::string CreateEmptyDirsFromStart(std::string start, 83 std::string path, mode_t mode) { 84 std::string temp = start + "/"; 85 for (size_t i = 1; i < path.length(); ++i) { 86 if (path[i] == '/') { 87 EXPECT_EQ(0, mkdir(temp.c_str(), mode)); 88 } 89 temp += path[i]; 90 } 91 // We reach the end of string before the last dir is created 92 EXPECT_EQ(0, mkdir(temp.c_str(), mode)); 93 return temp; 94 } 95 96 char *home_var_; 97 char *xdg_data_home_var_; 98 std::string old_home_dir_; 99 std::string old_xdg_data_home_; 100 std::string nssdir_; 101 std::string tmp_home_; 102 }; 103 104 class SysinitSetXdgUserDataHome : public Sysinit { 105 protected: 106 void SetUp() { 107 Sysinit::SetUp(); 108 ASSERT_EQ(0, setenv("XDG_DATA_HOME", tmp_home_.c_str(), 1)); 109 } 110 }; 111 112 class SysinitSetTrashXdgUserDataHome : public Sysinit { 113 protected: 114 void SetUp() { 115 Sysinit::SetUp(); 116 std::string trashPath = tmp_home_ + "/this/path/does/not/exist"; 117 ASSERT_EQ(0, setenv("XDG_DATA_HOME", trashPath.c_str(), 1)); 118 } 119 120 void TearDown() { 121 ASSERT_EQ(0, rmdir(tmp_home_.c_str())); 122 Sysinit::TearDown(); 123 } 124 }; 125 126 // Check if $HOME/.pki/nssdb is used if it exists 127 TEST_F(Sysinit, LegacyPath) { 128 nssdir_ = CreateEmptyDirsFromStart(tmp_home_, "/.pki/nssdb", 0760); 129 char *nssdb = getUserDB(); 130 ASSERT_EQ(nssdir_, nssdb); 131 PORT_Free(nssdb); 132 } 133 134 // Check if $HOME/.local/share/pki/nssdb is used if: 135 // - $HOME/.pki/nssdb does not exist; 136 // - XDG_DATA_HOME is not set. 137 TEST_F(Sysinit, XdgDefaultPath) { 138 nssdir_ = CreateEmptyDirsFromStart(tmp_home_, "/.local/share", 0755); 139 nssdir_ = CreateEmptyDirsFromStart(nssdir_, "/pki/nssdb", 0760); 140 char *nssdb = getUserDB(); 141 ASSERT_EQ(nssdir_, nssdb); 142 PORT_Free(nssdb); 143 } 144 145 // Check if ${XDG_DATA_HOME}/pki/nssdb is used if: 146 // - $HOME/.pki/nssdb does not exist; 147 // - XDG_DATA_HOME is set and the path exists. 148 TEST_F(SysinitSetXdgUserDataHome, XdgSetPath) { 149 // XDG_DATA_HOME is set to HOME 150 nssdir_ = CreateEmptyDirsFromStart(tmp_home_, "/pki/nssdb", 0760); 151 char *nssdb = getUserDB(); 152 ASSERT_EQ(nssdir_, nssdb); 153 PORT_Free(nssdb); 154 } 155 156 // Check if it fails when: 157 // - XDG_DATA_HOME is set to a path that does not exist; 158 // - $HOME/.pki/nssdb also does not exist. */ 159 TEST_F(SysinitSetTrashXdgUserDataHome, XdgSetToTrashPath) { 160 char *nssdb = getUserDB(); 161 ASSERT_EQ(nullptr, nssdb); 162 } 163 164 } // namespace nss_test