diff --git a/build.psm1 b/build.psm1 index 41021dde69..1599cce29b 100644 --- a/build.psm1 +++ b/build.psm1 @@ -201,9 +201,9 @@ function Start-PSBuild { try { Push-Location $Native - cmake -DCMAKE_BUILD_TYPE=Debug . - make -j - make test + Start-NativeExecution { cmake -DCMAKE_BUILD_TYPE=Debug . } + Start-NativeExecution { make -j } + Start-NativeExecution { ctest --verbose } } finally { Pop-Location } diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs index 073c1e5fe5..1a622ed288 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs @@ -866,6 +866,9 @@ namespace Microsoft.PowerShell.Commands private static string RetrieveProcessUserName(Process process, Cmdlet cmdlet) { string userName = null; +#if LINUX + userName = Platform.NonWindowsGetUserFromPid(process.Id); +#else IntPtr tokenUserInfo = IntPtr.Zero; IntPtr processTokenHandler = IntPtr.Zero; @@ -955,6 +958,7 @@ namespace Microsoft.PowerShell.Commands } } +#endif return userName; } diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 063ba49dda..eb9d3b2624 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -354,6 +354,18 @@ namespace System.Management.Automation } } + internal static string NonWindowsGetUserFromPid(int path) + { + if (!IsWindows) + { + return LinuxPlatform.GetUserFromPid(path); + } + else + { + throw new PlatformNotSupportedException(); + } + } + #if CORECLR internal static string NonWindowsGetFolderPath(SpecialFolder folder) { @@ -740,6 +752,11 @@ namespace System.Management.Automation return Native.FollowSymLink(path); } + public static string GetUserFromPid(int pid) + { + return Native.GetUserFromPid(pid); + } + [StructLayout(LayoutKind.Sequential)] internal class SetDateInfoInternal { @@ -809,6 +826,9 @@ namespace System.Management.Automation [return: MarshalAs(UnmanagedType.LPStr)] internal static extern string FollowSymLink([MarshalAs(UnmanagedType.LPStr)]string filePath); + [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] + [return: MarshalAs(UnmanagedType.LPStr)] + internal static extern string GetUserFromPid(int pid); } } diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index a9d4f2aafa..8dd8f96bea 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -960,21 +960,20 @@ namespace System.Management.Automation internal static bool IsAdministrator() { - // Porting note: only Windows supports the - // SecurityPrincipal API of .net for now assume Linux - // users have no concept of "Administrator" for now and - // specifically do not map to a check for root user - if (Platform.IsWindows) - { - System.Security.Principal.WindowsIdentity currentIdentity = System.Security.Principal.WindowsIdentity.GetCurrent(); - System.Security.Principal.WindowsPrincipal principal = new System.Security.Principal.WindowsPrincipal(currentIdentity); + // Porting note: only Windows supports the SecurityPrincipal API of .NET. Due to + // advanced privilege models, the correct approach on Unix is to assume the user has + // permissions, attempt the task, and error gracefully if the task fails due to + // permissions. To fit into PowerShell's existing model of pre-emptively checking + // permissions (which cannot be assumed on Unix), we "assume" the user is an + // administrator by returning true, thus nullifying this check on Unix. +#if LINUX + return true; +#else + System.Security.Principal.WindowsIdentity currentIdentity = System.Security.Principal.WindowsIdentity.GetCurrent(); + System.Security.Principal.WindowsPrincipal principal = new System.Security.Principal.WindowsPrincipal(currentIdentity); - return principal.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator); - } - else - { - return false; - } + return principal.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator); +#endif } internal static bool NativeItemExists(string path) diff --git a/src/libpsl-native/src/CMakeLists.txt b/src/libpsl-native/src/CMakeLists.txt index 5b2ec24199..8b3d0f19a9 100644 --- a/src/libpsl-native/src/CMakeLists.txt +++ b/src/libpsl-native/src/CMakeLists.txt @@ -1,4 +1,8 @@ add_library(psl-native SHARED + getstat.cpp + getpwuid.cpp + getuserfrompid.cpp + getfileowner.cpp getcurrentprocessorid.cpp getusername.cpp getcomputername.cpp diff --git a/src/libpsl-native/src/followsymlink.cpp b/src/libpsl-native/src/followsymlink.cpp index 6a77bcc52b..46576256e8 100644 --- a/src/libpsl-native/src/followsymlink.cpp +++ b/src/libpsl-native/src/followsymlink.cpp @@ -37,124 +37,68 @@ char* FollowSymLink(const char* fileName) { - errno = 0; + errno = 0; - // if filename is null, return null value if (!fileName) { errno = ERROR_INVALID_PARAMETER; return NULL; } - //if lstat in IsSymLink returns -1, path does not exist - if (IsSymLink(fileName) == -1) + // return null for non symlinks + if (!IsSymLink(fileName)) { return NULL; } - /*If the path is a symlink, the function return the absolute filepath if valid. if not valid, return null*/ - if (IsSymLink(fileName)) + // attempt to resolve with the absolute file path + char buffer[PATH_MAX]; + char* realPath = realpath(fileName, buffer); + + if (realPath) { - //Attempt to resolve with the absolute filepath - char actualpath[PATH_MAX+1]; - char* realPath = realpath(fileName, actualpath); - - //if realPath is null, go onto the readlink implementation - if (realPath == NULL) - { - char buffer[PATH_MAX]; - ssize_t sz = readlink(fileName, buffer, PATH_MAX); - - if (sz == -1) - { - switch(errno) - { - case EACCES: - errno = ERROR_ACCESS_DENIED; - break; - case EFAULT: - errno = ERROR_INVALID_ADDRESS; /*If the path is a symlink, the function return the absolute filepath if valid. if not valid, return null*/ - break; - case EINVAL: - errno = ERROR_INVALID_NAME; - case EIO: - errno = ERROR_GEN_FAILURE; - break; - case ELOOP: - errno = ERROR_STOPPED_ON_SYMLINK; - break; - case ENAMETOOLONG: - errno = ERROR_BAD_PATH_NAME; - break; - case ENOENT: - errno = ERROR_FILE_NOT_FOUND; - break; - case ENOMEM: - errno = ERROR_OUTOFMEMORY; - break; - case ENOTDIR: - errno = ERROR_BAD_PATH_NAME; - break; - default: - errno = ERROR_INVALID_FUNCTION; - } + return strndup(realPath, strlen(realPath) + 1); + } - return NULL; - } - - buffer[sz] = '\0'; - return strndup(buffer, sz + 1); - } - else + // if the path wasn't resolved, use readlink + ssize_t sz = readlink(fileName, buffer, PATH_MAX); + if (sz == -1) + { + switch(errno) { - return strndup(realPath, strlen(realPath) + 1 ); + case EACCES: + errno = ERROR_ACCESS_DENIED; + break; + case EFAULT: + errno = ERROR_INVALID_ADDRESS; + break; + case EINVAL: + errno = ERROR_INVALID_NAME; + case EIO: + errno = ERROR_GEN_FAILURE; + break; + case ELOOP: + errno = ERROR_STOPPED_ON_SYMLINK; + break; + case ENAMETOOLONG: + errno = ERROR_BAD_PATH_NAME; + break; + case ENOENT: + errno = ERROR_FILE_NOT_FOUND; + break; + case ENOMEM: + errno = ERROR_OUTOFMEMORY; + break; + case ENOTDIR: + errno = ERROR_BAD_PATH_NAME; + break; + default: + errno = ERROR_INVALID_FUNCTION; } + + return NULL; } - - else - { - char buffer[PATH_MAX]; - ssize_t sz = readlink(fileName, buffer, PATH_MAX); - - if (sz == -1) - { - switch(errno) - { - case EACCES: - errno = ERROR_ACCESS_DENIED; - break; - case EFAULT: - errno = ERROR_INVALID_ADDRESS; /*If the path is a symlink, the function return the absolute filepath if valid. if not valid, return null*/ - break; - case EINVAL: - errno = ERROR_INVALID_NAME; - case EIO: - errno = ERROR_GEN_FAILURE; - break; - case ELOOP: - errno = ERROR_STOPPED_ON_SYMLINK; - break; - case ENAMETOOLONG: - errno = ERROR_BAD_PATH_NAME; - break; - case ENOENT: - errno = ERROR_FILE_NOT_FOUND; - break; - case ENOMEM: - errno = ERROR_OUTOFMEMORY; - break; - case ENOTDIR: - errno = ERROR_BAD_PATH_NAME; - break; - default: - errno = ERROR_INVALID_FUNCTION; - } - return NULL; - } - - buffer[sz] = '\0'; - return strndup(buffer, sz + 1); - - } + buffer[sz] = '\0'; + return strndup(buffer, sz + 1); } diff --git a/src/libpsl-native/src/getfileowner.cpp b/src/libpsl-native/src/getfileowner.cpp new file mode 100644 index 0000000000..c1bd5b69f6 --- /dev/null +++ b/src/libpsl-native/src/getfileowner.cpp @@ -0,0 +1,50 @@ +//! @file getfileowner.cpp +//! @author Andrew Schwartzmeyer +//! @brief returns the owner of a file + +#include +#include +#include +#include +#include +#include +#include "getstat.h" +#include "getpwuid.h" +#include "getfileowner.h" + +//! @brief GetFileOwner returns the owner of a file +//! +//! GetFileOwner +//! +//! @param[in] fileName +//! @parblock +//! A pointer to the buffer that contains the file name +//! +//! char* is marshaled as an LPStr, which on Linux is UTF-8. +//! @endparblock +//! +//! @exception errno Passes this error via errno to GetLastError: +//! - ERROR_INVALID_PARAMETER: parameter is not valid +//! +//! @retval file owner, or NULL if unsuccessful +//! +char* GetFileOwner(const char* fileName) +{ + int32_t ret = 0; + errno = 0; + + if (!fileName) + { + errno = ERROR_INVALID_PARAMETER; + return NULL; + } + + struct stat buf; + ret = GetStat(fileName, &buf); + if (ret != 0) + { + return NULL; + } + + return GetPwUid(buf.st_uid); +} diff --git a/src/libpsl-native/src/getfileowner.h b/src/libpsl-native/src/getfileowner.h new file mode 100644 index 0000000000..7da83dccca --- /dev/null +++ b/src/libpsl-native/src/getfileowner.h @@ -0,0 +1,9 @@ +#pragma once + +#include "pal.h" + +PAL_BEGIN_EXTERNC + +char* GetFileOwner(const char* fileName); + +PAL_END_EXTERNC diff --git a/src/libpsl-native/src/getfullyqualifiedname.cpp b/src/libpsl-native/src/getfullyqualifiedname.cpp index 44178a0a5a..bc4fe1b194 100644 --- a/src/libpsl-native/src/getfullyqualifiedname.cpp +++ b/src/libpsl-native/src/getfullyqualifiedname.cpp @@ -27,12 +27,12 @@ char *GetFullyQualifiedName() char *computerName = GetComputerName(); if (computerName == NULL) { - return NULL; + return NULL; } if (strchr(computerName, '.') != NULL) { - return computerName; + return computerName; } struct addrinfo hints, *info; @@ -51,7 +51,7 @@ char *GetFullyQualifiedName() if (getaddrinfo(computerName, "http", &hints, &info) != 0) { errno = ERROR_BAD_NET_NAME; - return NULL; + return NULL; } // info is actually a link-list. We'll just return the first full name diff --git a/src/libpsl-native/src/getpwuid.cpp b/src/libpsl-native/src/getpwuid.cpp new file mode 100644 index 0000000000..62263067e2 --- /dev/null +++ b/src/libpsl-native/src/getpwuid.cpp @@ -0,0 +1,81 @@ +//! @file getpwuid.cpp +//! @author Andrew Schwartzmeyer +//! @brief returns the username for a uid + +#include +#include +#include +#include +#include +#include +#include "getpwuid.h" + +//! @brief GetPwUid returns the username for a uid +//! +//! GetPwUid +//! +//! @param[in] uid +//! @parblock +//! The user identifier to lookup. +//! @endparblock +//! +//! @exception errno Passes these errors via errno to GetLastError: +//! - ERROR_NO_SUCH_USER: user lookup unsuccessful +//! - ERROR_OUTOFMEMORY insufficient kernel memory +//! - ERROR_GEN_FAILURE: anything else +//! +//! @retval username as UTF-8 string, or NULL if unsuccessful +//! +char* GetPwUid(uid_t uid) +{ + int32_t ret = 0; + struct passwd pwd; + struct passwd* result = NULL; + char* buf; + + int buflen = sysconf(_SC_GETPW_R_SIZE_MAX); + if (buflen < 1) + { + buflen = 2048; + } + +allocate: + buf = (char*)calloc(buflen, sizeof(char)); + + ret = getpwuid_r(uid, &pwd, buf, buflen, &result); + + if (ret != 0) + { + switch(errno) + { + case ERANGE: + free(buf); + buflen *= 2; + goto allocate; + case ENOENT: + case ESRCH: + case EBADF: + case EPERM: + errno = ERROR_NO_SUCH_USER; + break; + case ENOMEM: + errno = ERROR_OUTOFMEMORY; + break; + default: + errno = ERROR_GEN_FAILURE; + } + return NULL; + } + + // no result + if (result == NULL) + { + return NULL; + } + + // allocate copy on heap so CLR can free it + size_t userlen = strnlen(pwd.pw_name, buflen); + char* username = strndup(pwd.pw_name, userlen); + free(buf); + return username; +} diff --git a/src/libpsl-native/src/getpwuid.h b/src/libpsl-native/src/getpwuid.h new file mode 100644 index 0000000000..cbf2cca911 --- /dev/null +++ b/src/libpsl-native/src/getpwuid.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include "pal.h" + +PAL_BEGIN_EXTERNC + +char* GetPwUid(uid_t uid); + +PAL_END_EXTERNC diff --git a/src/libpsl-native/src/getstat.cpp b/src/libpsl-native/src/getstat.cpp new file mode 100644 index 0000000000..3e89d1a6ed --- /dev/null +++ b/src/libpsl-native/src/getstat.cpp @@ -0,0 +1,96 @@ +//! @file getstat.cpp +//! @author Andrew Schwartzmeyer +//! @brief returns the stat of a file + +#include +#include +#include +#include +#include +#include +#include "getstat.h" + +//! @brief GetStat returns the stat of a file. This simply delegates to the +//! stat() system call and maps errno to the expected values for GetLastError. +//! +//! GetStat +//! +//! @param[in] path +//! @parblock +//! A pointer to the buffer that contains the file name +//! +//! char* is marshaled as an LPStr, which on Linux is UTF-8. +//! @endparblock +//! +//! @param[in] stat +//! @parblock +//! A pointer to the buffer in which to place the stat information +//! @endparblock +//! +//! @exception errno Passes these errors via errno to GetLastError: +//! - ERROR_INVALID_PARAMETER: parameter is not valid +//! - ERROR_FILE_NOT_FOUND: file does not exist +//! - ERROR_ACCESS_DENIED: access is denied +//! - ERROR_INVALID_ADDRESS: attempt to access invalid address +//! - ERROR_STOPPED_ON_SYMLINK: too many symbolic links +//! - ERROR_GEN_FAILURE: I/O error occurred +//! - ERROR_INVALID_NAME: file provided is not a symbolic link +//! - ERROR_INVALID_FUNCTION: incorrect function +//! - ERROR_BAD_PATH_NAME: pathname is too long +//! - ERROR_OUTOFMEMORY insufficient kernel memory +//! +//! @retval 0 if successful +//! @retval -1 if failed +//! + +int32_t GetStat(const char* path, struct stat* buf) +{ + errno = 0; + + if (!path) + { + errno = ERROR_INVALID_PARAMETER; + return -1; + } + + int32_t ret = stat(path, buf); + + if (ret != 0) + { + switch(errno) + { + case EACCES: + errno = ERROR_ACCESS_DENIED; + break; + case EBADF: + errno = ERROR_FILE_NOT_FOUND; + break; + case EFAULT: + errno = ERROR_INVALID_ADDRESS; + break; + case ELOOP: + errno = ERROR_STOPPED_ON_SYMLINK; + break; + case ENAMETOOLONG: + errno = ERROR_GEN_FAILURE; + break; + case ENOENT: + errno = ERROR_FILE_NOT_FOUND; + break; + case ENOMEM: + errno = ERROR_NO_SUCH_USER; + break; + case ENOTDIR: + errno = ERROR_INVALID_NAME; + break; + case EOVERFLOW: + errno = ERROR_BUFFER_OVERFLOW; + break; + default: + errno = ERROR_INVALID_FUNCTION; + } + return -1; + } + + return 0; +} diff --git a/src/libpsl-native/src/getstat.h b/src/libpsl-native/src/getstat.h new file mode 100644 index 0000000000..00bc26e9fa --- /dev/null +++ b/src/libpsl-native/src/getstat.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include "pal.h" + +PAL_BEGIN_EXTERNC + +int32_t GetStat(const char* path, struct stat* buf); + +PAL_END_EXTERNC diff --git a/src/libpsl-native/src/getuserfrompid.cpp b/src/libpsl-native/src/getuserfrompid.cpp new file mode 100644 index 0000000000..fd148a9ff2 --- /dev/null +++ b/src/libpsl-native/src/getuserfrompid.cpp @@ -0,0 +1,47 @@ +#include +#include +#include +#include +#include "pal.h" +#include "getfileowner.h" +#include "getpwuid.h" +#include "getuserfrompid.h" + +char* GetUserFromPid(pid_t pid) +{ + +#if defined(__linux__) + + // Get effective owner of pid from procfs + std::stringstream ss; + ss << "/proc/" << pid; + std::string path; + ss >> path; + + return GetFileOwner(path.c_str()); + +#elif defined(__APPLE__) && defined(__MACH__) + + // Get effective owner of pid from sysctl + struct kinfo_proc oldp; + size_t oldlenp = sizeof(oldp); + int name[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; + u_int namelen = sizeof(name)/sizeof(int); + + // Read-only query + int ret = sysctl(name, namelen, &oldp, &oldlenp, NULL, 0); + if (ret != 0 || oldlenp == 0) + { + errno = ERROR_GEN_FAILURE; + return NULL; + } + + return GetPwUid(oldp.kp_eproc.e_ucred.cr_uid); + +#else + + return NULL; + +#endif + +} diff --git a/src/libpsl-native/src/getuserfrompid.h b/src/libpsl-native/src/getuserfrompid.h new file mode 100644 index 0000000000..c019f475fc --- /dev/null +++ b/src/libpsl-native/src/getuserfrompid.h @@ -0,0 +1,9 @@ +#pragma once + +#include "pal.h" + +PAL_BEGIN_EXTERNC + +char* GetUserFromPid(pid_t pid); + +PAL_END_EXTERNC diff --git a/src/libpsl-native/src/getusername.cpp b/src/libpsl-native/src/getusername.cpp index 0efab96688..56c3d6d080 100644 --- a/src/libpsl-native/src/getusername.cpp +++ b/src/libpsl-native/src/getusername.cpp @@ -2,64 +2,16 @@ //! @author Andrew Schwartzmeyer //! @brief Implements GetUserName for Linux -#include -#include #include -#include -#include +#include "getpwuid.h" #include "getusername.h" //! @brief GetUserName retrieves the name of the user associated with //! the current thread. //! -//! @exception errno Passes these errors via errno to GetLastError: -//! - ERROR_INVALID_PARAMETER: parameter is not valid -//! - ERROR_NO_SUCH_USER: there was no corresponding user -//! - ERROR_GEN_FAILURE: sysconf() or getpwuid() failed for unknown reasons -//! //! @retval username as UTF-8 string, or null if unsuccessful char* GetUserName() { - errno = 0; - - struct passwd pwd; - struct passwd* result; - // gets the initial suggested size for buf - int buflen = sysconf(_SC_GETPW_R_SIZE_MAX); - if (buflen == -1) - { - errno = ERROR_GEN_FAILURE; - return NULL; - } - std::string buf(buflen, 0); - // geteuid() gets the effective user ID of the calling process, and is always successful - int ret = getpwuid_r(geteuid(), &pwd, &buf[0], buflen, &result); - - // Map errno to Win32 Error Codes - if (ret) - { - switch (errno) - { - case ENOENT: - case ESRCH: - case EBADF: - case EPERM: - errno = ERROR_NO_SUCH_USER; - break; - default: - errno = ERROR_GEN_FAILURE; - } - return NULL; - } - - // Check if no user matched - if (result == NULL) - { - errno = ERROR_NO_SUCH_USER; - return NULL; - } - - // allocate copy on heap so CLR can free it - return strdup(result->pw_name); + return GetPwUid(geteuid()); } diff --git a/src/libpsl-native/test/CMakeLists.txt b/src/libpsl-native/test/CMakeLists.txt index 4ddc538361..ed4440d2a3 100644 --- a/src/libpsl-native/test/CMakeLists.txt +++ b/src/libpsl-native/test/CMakeLists.txt @@ -1,7 +1,9 @@ add_subdirectory(googletest) add_executable(psl-native-test + test-getfileowner.cpp test-locale.cpp + test-getuserfrompid.cpp test-getcurrentprocessid.cpp test-getusername.cpp test-getcomputername.cpp diff --git a/src/libpsl-native/test/test-createsymlink.cpp b/src/libpsl-native/test/test-createsymlink.cpp index abc0646c61..7bb9997b30 100644 --- a/src/libpsl-native/test/test-createsymlink.cpp +++ b/src/libpsl-native/test/test-createsymlink.cpp @@ -32,19 +32,19 @@ protected: // First create a temp file int fd = mkstemp(fileTemplateBuf); EXPECT_TRUE(fd != -1); - file = fileTemplateBuf; + file = fileTemplateBuf; - // Create a temp directory - dir = mkdtemp(dirTemplateBuf); + // Create a temp directory + dir = mkdtemp(dirTemplateBuf); EXPECT_TRUE(dir != NULL); // Create symbolic link to file - int ret1 = CreateSymLink(fileSymLink.c_str(), file); - EXPECT_EQ(ret1, 1); - + int ret1 = CreateSymLink(fileSymLink.c_str(), file); + EXPECT_EQ(ret1, 1); + // Create symbolic link to directory - int ret2 = CreateSymLink(dirSymLink.c_str(), dir); - EXPECT_EQ(ret2, 1); + int ret2 = CreateSymLink(dirSymLink.c_str(), dir); + EXPECT_EQ(ret2, 1); } ~CreateSymLinkTest() @@ -52,16 +52,16 @@ protected: int ret; ret = unlink(fileSymLink.c_str()); - EXPECT_EQ(0, ret); + EXPECT_EQ(0, ret); ret = unlink(dirSymLink.c_str()); - EXPECT_EQ(0, ret); + EXPECT_EQ(0, ret); ret = unlink(file); - EXPECT_EQ(0, ret); + EXPECT_EQ(0, ret); - ret = rmdir(dir); - EXPECT_EQ(0, ret); + ret = rmdir(dir); + EXPECT_EQ(0, ret); } }; @@ -77,7 +77,7 @@ TEST_F(CreateSymLinkTest, FilePathNameDoesNotExist) std::string invalidFile = "/tmp/symlinktest_invalidFile"; std::string invalidLink = "/tmp/symlinktest_invalidLink"; - // make sure neither exists + // make sure neither exists unlink(invalidFile.c_str()); unlink(invalidLink.c_str()); @@ -97,7 +97,9 @@ TEST_F(CreateSymLinkTest, SymLinkToFile) EXPECT_EQ(1, retVal); std::string target = FollowSymLink(fileSymLink.c_str()); - EXPECT_EQ(target, file); + char buffer[PATH_MAX]; + std::string expected = realpath(file, buffer); + EXPECT_EQ(target, expected); } TEST_F(CreateSymLinkTest, SymLinkToDirectory) @@ -106,7 +108,9 @@ TEST_F(CreateSymLinkTest, SymLinkToDirectory) EXPECT_EQ(1, retVal); std::string target = FollowSymLink(dirSymLink.c_str()); - EXPECT_EQ(target, dir); + char buffer[PATH_MAX]; + std::string expected = realpath(dir, buffer); + EXPECT_EQ(target, expected); } TEST_F(CreateSymLinkTest, SymLinkAgain) diff --git a/src/libpsl-native/test/test-getfileowner.cpp b/src/libpsl-native/test/test-getfileowner.cpp new file mode 100644 index 0000000000..275c63ed11 --- /dev/null +++ b/src/libpsl-native/test/test-getfileowner.cpp @@ -0,0 +1,25 @@ +//! @file test-getfileowner.cpp +//! @author Andrew Schwartzmeyer +//! @brief Tests GetFileOwner + +#include +#include +#include +#include "getfileowner.h" + +TEST(GetFileOwnerTest, CanGetOwnerOfRoot) +{ + EXPECT_STREQ(GetFileOwner("/"), "root"); +} + +TEST(GetFileOwnerTest, CannotGetOwnerOfFakeFile) +{ + EXPECT_STREQ(GetFileOwner("SomeMadeUpFileNameThatDoesNotExist"), NULL); + EXPECT_EQ(errno, ERROR_FILE_NOT_FOUND); +} + +TEST(GetFileOwnerTest, ReturnsNullForNullInput) +{ + EXPECT_STREQ(GetFileOwner(NULL), NULL); + EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); +} diff --git a/src/libpsl-native/test/test-getfullyqualifiedname.cpp b/src/libpsl-native/test/test-getfullyqualifiedname.cpp index 7c0353cd1d..94c2947d6f 100644 --- a/src/libpsl-native/test/test-getfullyqualifiedname.cpp +++ b/src/libpsl-native/test/test-getfullyqualifiedname.cpp @@ -3,38 +3,35 @@ //! @brief Unit tests for GetFullyQualifiedName #include +#include "getcomputername.h" #include "getfullyqualifiedname.h" #include #include #include #include -//! Test fixture for GetComputerNameTest -class GetFullyQualifiedNameTest : public ::testing::Test -{ -}; - -TEST_F(GetFullyQualifiedNameTest, ValidateLinuxGetFullyQualifiedDomainName) +TEST(GetFullyQualifiedNameTest, ValidateLinuxGetFullyQualifiedDomainName) { std::string actual(GetFullyQualifiedName()); - std::string hostname(_POSIX_HOST_NAME_MAX, 0); - ASSERT_FALSE(gethostname(&hostname[0], hostname.length())); - // trim null characters from string - hostname = std::string(hostname.c_str()); + std::string hostname(GetComputerName()); - struct addrinfo hints, *info; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_CANONNAME; - ASSERT_FALSE(getaddrinfo(hostname.c_str(), "http", &hints, &info)); + // FQDN starts with hostname (which may be fully qualified) + EXPECT_LE(hostname, actual); - // Compare hostname part of FQDN - ASSERT_EQ(hostname, actual.substr(0, hostname.length())); + // hostname did not include domain name, so test it separately + if (hostname < actual) + { + struct addrinfo hints, *info; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + EXPECT_FALSE(getaddrinfo(hostname.c_str(), "http", &hints, &info)); - // Compare canonical name to FQDN - ASSERT_EQ(info->ai_canonname, actual); + // Compare canonical name to FQDN + EXPECT_STREQ(info->ai_canonname, actual.c_str()); - freeaddrinfo(info); + freeaddrinfo(info); + } } diff --git a/src/libpsl-native/test/test-getuserfrompid.cpp b/src/libpsl-native/test/test-getuserfrompid.cpp new file mode 100644 index 0000000000..ca6d866c63 --- /dev/null +++ b/src/libpsl-native/test/test-getuserfrompid.cpp @@ -0,0 +1,13 @@ +//! @file test-getuserfrompid.cpp +//! @author Andrew Schwartzmeyer +//! @brief Unit tests for GetUserFromPid + +#include +#include +#include "getuserfrompid.h" + +TEST(GetUserFromPid, Success) +{ + char* expected = getpwuid(geteuid())->pw_name; + EXPECT_STREQ(GetUserFromPid(getpid()), expected); +} diff --git a/src/libpsl-native/test/test-getusername.cpp b/src/libpsl-native/test/test-getusername.cpp index 2ccb29f68a..3f4751276f 100644 --- a/src/libpsl-native/test/test-getusername.cpp +++ b/src/libpsl-native/test/test-getusername.cpp @@ -2,9 +2,6 @@ //! @author Andrew Schwartzmeyer //! @brief Unit tests for GetUserName -#include -#include -#include #include #include #include "getusername.h" @@ -12,6 +9,5 @@ TEST(GetUserName, Success) { char* expected = getpwuid(geteuid())->pw_name; - ASSERT_TRUE(expected != NULL); - ASSERT_EQ(GetUserName(), std::string(expected)); + EXPECT_STREQ(GetUserName(), expected); } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Get-Process.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Get-Process.Tests.ps1 index d2ac52def5..64a9f7fe46 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Get-Process.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Get-Process.Tests.ps1 @@ -1,4 +1,8 @@ Describe "Get-Process" { + It "Should support -IncludeUserName" { + (Get-Process powershell -IncludeUserName | Select-Object -First 1).UserName | Should Match $env:USERNAME + } + # These tests are no good, please replace! It "Should return a type of Object[] for Get-Process cmdlet" -Pending:$IsOSX { (Get-Process).GetType().BaseType | Should Be 'array'