Skip to content

Commit

Permalink
Bug 818686 - XDG Base Directory Specification support with fallback, …
Browse files Browse the repository at this point in the history
…r=mt

Summary:
We check if $HOME/.pki and $HOME/.pki/nssdb exist; if they do, then we use
this path. Otherwise, use ${XDG_DATA_HOME:-$HOME/.local/share}/pki/nssdb

Test Plan:
Create dummy empty dir and set HOME to it. Then, check if getUserDb returns:
1. $HOME/.pki/nssdb when this path exists;
2. $HOME/.local/share/pki/nssdb when $HOME/.pki/nssdb does not and XDG_DATA_HOME is not defined;
3. $XDG_DATA_HOME/pki/nssdb when $HOME/.pki/nssdb does not exist and XDG_DATA_HOME is defined.

Reviewers: mt

Reviewed By: mt

Bug #: 818686

Differential Revision: https://phabricator.services.mozilla.com/D14007

--HG--
extra : source : 45f82855824be40a6a2b74632dda5e9e6f89a5d0
  • Loading branch information
denisfa committed Jan 9, 2019
1 parent bad4d9c commit 7f21d4f
Show file tree
Hide file tree
Showing 14 changed files with 404 additions and 18 deletions.
8 changes: 8 additions & 0 deletions automation/abi-check/expected-report-libnsssysinit.so.txt
@@ -0,0 +1,8 @@
Function symbols changes summary: 2 Removed, 0 Added function symbols not referenced by debug info
Variable symbols changes summary: 0 Removed, 0 Added variable symbol not referenced by debug info

2 Removed function symbols not referenced by debug info:

_fini
_init

10 changes: 10 additions & 0 deletions gtests/Makefile
Expand Up @@ -26,6 +26,16 @@ include $(CORE_DEPTH)/coreconf/config.mk
# (4) Include "local" platform-dependent assignments (OPTIONAL). #
#######################################################################

# Don't build sysinit gtests unless we are also building libnsssysinit.
# See lib/Makefile for the corresponding rules.
ifndef MOZILLA_CLIENT
ifeq ($(OS_ARCH),Linux)
ifneq ($(NSS_BUILD_UTIL_ONLY),1)
SYSINIT_GTEST=sysinit_gtest
endif
endif
endif


#######################################################################
# (5) Execute "global" rules. (OPTIONAL) #
Expand Down
1 change: 1 addition & 0 deletions gtests/manifest.mn
Expand Up @@ -26,6 +26,7 @@ NSS_SRCDIRS = \
pk11_gtest \
softoken_gtest \
ssl_gtest \
$(SYSINIT_GTEST) \
nss_bogo_shim \
$(NULL)
endif
Expand Down
43 changes: 43 additions & 0 deletions gtests/sysinit_gtest/Makefile
@@ -0,0 +1,43 @@
#! gmake
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

#######################################################################
# (1) Include initial platform-independent assignments (MANDATORY). #
#######################################################################

include manifest.mn

#######################################################################
# (2) Include "global" configuration information. (OPTIONAL) #
#######################################################################

include $(CORE_DEPTH)/coreconf/config.mk

#######################################################################
# (3) Include "component" configuration information. (OPTIONAL) #
#######################################################################


#######################################################################
# (4) Include "local" platform-dependent assignments (OPTIONAL). #
#######################################################################

include ../common/gtest.mk

#######################################################################
# (5) Execute "global" rules. (OPTIONAL) #
#######################################################################

include $(CORE_DEPTH)/coreconf/rules.mk

#######################################################################
# (6) Execute "component" rules. (OPTIONAL) #
#######################################################################


#######################################################################
# (7) Execute "local" rules. (OPTIONAL). #
#######################################################################
164 changes: 164 additions & 0 deletions gtests/sysinit_gtest/getUserDB_unittest.cc
@@ -0,0 +1,164 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gtest/gtest.h"
#include "prenv.h"
#include "seccomon.h"

#include <stdlib.h>
#include <string>
#include <unistd.h>
#include <sys/stat.h>

namespace nss_test {

// Return the path to user's NSS database.
extern "C" char *getUserDB(void);

class Sysinit : public ::testing::Test {
protected:
void SetUp() {
home_var_ = PR_GetEnvSecure("HOME");
if (home_var_) {
old_home_dir_ = home_var_;
}
xdg_data_home_var_ = PR_GetEnvSecure("XDG_DATA_HOME");
if (xdg_data_home_var_) {
old_xdg_data_home_ = xdg_data_home_var_;
ASSERT_EQ(0, unsetenv("XDG_DATA_HOME"));
}
char tmp[] = "/tmp/nss-tmp.XXXXXX";
tmp_home_ = mkdtemp(tmp);
ASSERT_EQ(0, setenv("HOME", tmp_home_.c_str(), 1));
}

void TearDown() {
// Set HOME back to original
if (home_var_) {
ASSERT_EQ(0, setenv("HOME", old_home_dir_.c_str(), 1));
} else {
ASSERT_EQ(0, unsetenv("HOME"));
}
// Set XDG_DATA_HOME back to original
if (xdg_data_home_var_) {
ASSERT_EQ(0, setenv("XDG_DATA_HOME", old_xdg_data_home_.c_str(), 1));
}
// Remove test dirs.
if (!nssdir_.empty()) {
ASSERT_EQ(0, RemoveEmptyDirsFromStart(nssdir_, tmp_home_));
}
}

// Remove all dirs within @start from @path containing only empty dirs.
// Assumes @start already exists.
// Upon successful completion, return 0. Otherwise, -1.
static int RemoveEmptyDirsFromStart(std::string path, std::string start) {
if (path.find(start) == std::string::npos) {
return -1;
}
std::string temp = path;
if (rmdir(temp.c_str())) {
return -1;
}
for (size_t i = temp.length() - 1; i > start.length(); --i) {
if (temp[i] == '/') {
temp[i] = '\0';
if (rmdir(temp.c_str())) {
return -1;
}
}
}
if (rmdir(start.c_str())) {
return -1;
}
return 0;
}

// Create empty dirs appending @path to @start with mode @mode.
// Assumes @start already exists.
// Upon successful completion, return the string @start + @path.
static std::string CreateEmptyDirsFromStart(std::string start,
std::string path, mode_t mode) {
std::string temp = start + "/";
for (size_t i = 1; i < path.length(); ++i) {
if (path[i] == '/') {
EXPECT_EQ(0, mkdir(temp.c_str(), mode));
}
temp += path[i];
}
// We reach the end of string before the last dir is created
EXPECT_EQ(0, mkdir(temp.c_str(), mode));
return temp;
}

char *home_var_;
char *xdg_data_home_var_;
std::string old_home_dir_;
std::string old_xdg_data_home_;
std::string nssdir_;
std::string tmp_home_;
};

class SysinitSetXdgUserDataHome : public Sysinit {
protected:
void SetUp() {
Sysinit::SetUp();
ASSERT_EQ(0, setenv("XDG_DATA_HOME", tmp_home_.c_str(), 1));
}
};

class SysinitSetTrashXdgUserDataHome : public Sysinit {
protected:
void SetUp() {
Sysinit::SetUp();
std::string trashPath = tmp_home_ + "/this/path/does/not/exist";
ASSERT_EQ(0, setenv("XDG_DATA_HOME", trashPath.c_str(), 1));
}

void TearDown() {
ASSERT_EQ(0, rmdir(tmp_home_.c_str()));
Sysinit::TearDown();
}
};

// Check if $HOME/.pki/nssdb is used if it exists
TEST_F(Sysinit, LegacyPath) {
nssdir_ = CreateEmptyDirsFromStart(tmp_home_, "/.pki/nssdb", 0760);
char *nssdb = getUserDB();
ASSERT_EQ(nssdir_, nssdb);
PORT_Free(nssdb);
}

// Check if $HOME/.local/share/pki/nssdb is used if:
// - $HOME/.pki/nssdb does not exist;
// - XDG_DATA_HOME is not set.
TEST_F(Sysinit, XdgDefaultPath) {
nssdir_ = CreateEmptyDirsFromStart(tmp_home_, "/.local/share", 0755);
nssdir_ = CreateEmptyDirsFromStart(nssdir_, "/pki/nssdb", 0760);
char *nssdb = getUserDB();
ASSERT_EQ(nssdir_, nssdb);
PORT_Free(nssdb);
}

// Check if ${XDG_DATA_HOME}/pki/nssdb is used if:
// - $HOME/.pki/nssdb does not exist;
// - XDG_DATA_HOME is set and the path exists.
TEST_F(SysinitSetXdgUserDataHome, XdgSetPath) {
// XDG_DATA_HOME is set to HOME
nssdir_ = CreateEmptyDirsFromStart(tmp_home_, "/pki/nssdb", 0760);
char *nssdb = getUserDB();
ASSERT_EQ(nssdir_, nssdb);
PORT_Free(nssdb);
}

// Check if it fails when:
// - XDG_DATA_HOME is set to a path that does not exist;
// - $HOME/.pki/nssdb also does not exist. */
TEST_F(SysinitSetTrashXdgUserDataHome, XdgSetToTrashPath) {
char *nssdb = getUserDB();
ASSERT_EQ(nullptr, nssdb);
}

} // namespace nss_test
27 changes: 27 additions & 0 deletions gtests/sysinit_gtest/manifest.mn
@@ -0,0 +1,27 @@
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
CORE_DEPTH = ../..
DEPTH = ../..

MODULE = nss

CPPSRCS = \
getUserDB_unittest.cc \
sysinit_gtest.cc \
$(NULL)

INCLUDES += -I$(CORE_DEPTH)/gtests/google_test/gtest/include \
-I$(CORE_DEPTH)/gtests/common

REQUIRES = nspr nss libdbm gtest

PROGRAM = sysinit_gtest

EXTRA_LIBS = \
$(DIST)/lib/$(LIB_PREFIX)gtest.$(LIB_SUFFIX) $(EXTRA_OBJS) \
$(DIST)/lib/$(LIB_PREFIX)nsssysinit.$(LIB_SUFFIX) \
$(NULL)

USE_STATIC_LIBS = 1
9 changes: 9 additions & 0 deletions gtests/sysinit_gtest/sysinit_gtest.cc
@@ -0,0 +1,9 @@
#define GTEST_HAS_RTTI 0
#include "gtest/gtest.h"

int main(int argc, char** argv) {
// Start the tests
::testing::InitGoogleTest(&argc, argv);
int rv = RUN_ALL_TESTS();
return rv;
}
35 changes: 35 additions & 0 deletions gtests/sysinit_gtest/sysinit_gtest.gyp
@@ -0,0 +1,35 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
{
'includes': [
'../../coreconf/config.gypi',
'../common/gtest.gypi'
],
'targets': [
{
'target_name': 'sysinit_gtest',
'type': 'executable',
'sources': [
'sysinit_gtest.cc',
'getUserDB_unittest.cc',
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports',
'<(DEPTH)/gtests/google_test/google_test.gyp:gtest',
'<(DEPTH)/lib/sysinit/sysinit.gyp:nsssysinit_static'
]
}
],
'target_defaults': {
'include_dirs': [
'../../lib/sysinit'
],
'defines': [
'NSS_USE_STATIC_LIBS'
]
},
'variables': {
'module': 'nss'
}
}
10 changes: 6 additions & 4 deletions lib/sysinit/manifest.mn
Expand Up @@ -2,14 +2,16 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

CORE_DEPTH = ../..

# MODULE public and private header directories are implicitly REQUIRED.
MODULE = nss

CSRCS = nsssysinit.c
CSRCS = \
nsssysinit.c \
$(NULL)

LIBRARY_NAME = nsssysinit
#LIBRARY_VERSION = 3
MAPFILE = $(OBJDIR)/nsssysinit.def

# This part of the code, including all sub-dirs, can be optimized for size
export ALLOW_OPT_CODE_SIZE = 1

0 comments on commit 7f21d4f

Please sign in to comment.