mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
Merge pull request #1352 from PowerShell/andschwa/username
Implement Get-Process -IncludeUserName for Linux
This commit is contained in:
+3
-3
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
add_library(psl-native SHARED
|
||||
getstat.cpp
|
||||
getpwuid.cpp
|
||||
getuserfrompid.cpp
|
||||
getfileowner.cpp
|
||||
getcurrentprocessorid.cpp
|
||||
getusername.cpp
|
||||
getcomputername.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);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
//! @file getfileowner.cpp
|
||||
//! @author Andrew Schwartzmeyer <andschwa@microsoft.com>
|
||||
//! @brief returns the owner of a file
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <pwd.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#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);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "pal.h"
|
||||
|
||||
PAL_BEGIN_EXTERNC
|
||||
|
||||
char* GetFileOwner(const char* fileName);
|
||||
|
||||
PAL_END_EXTERNC
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
//! @file getpwuid.cpp
|
||||
//! @author Andrew Schwartzmeyer <andschwa@microsoft.com>
|
||||
//! @brief returns the username for a uid
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <pwd.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "pal.h"
|
||||
|
||||
PAL_BEGIN_EXTERNC
|
||||
|
||||
char* GetPwUid(uid_t uid);
|
||||
|
||||
PAL_END_EXTERNC
|
||||
@@ -0,0 +1,96 @@
|
||||
//! @file getstat.cpp
|
||||
//! @author Andrew Schwartzmeyer <andschwa@microsoft.com>
|
||||
//! @brief returns the stat of a file
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <pwd.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include "pal.h"
|
||||
|
||||
PAL_BEGIN_EXTERNC
|
||||
|
||||
int32_t GetStat(const char* path, struct stat* buf);
|
||||
|
||||
PAL_END_EXTERNC
|
||||
@@ -0,0 +1,47 @@
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <errno.h>
|
||||
#include <sys/sysctl.h>
|
||||
#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
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "pal.h"
|
||||
|
||||
PAL_BEGIN_EXTERNC
|
||||
|
||||
char* GetUserFromPid(pid_t pid);
|
||||
|
||||
PAL_END_EXTERNC
|
||||
@@ -2,64 +2,16 @@
|
||||
//! @author Andrew Schwartzmeyer <andschwa@microsoft.com>
|
||||
//! @brief Implements GetUserName for Linux
|
||||
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <unistd.h>
|
||||
#include <string>
|
||||
#include <pwd.h>
|
||||
#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());
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
//! @file test-getfileowner.cpp
|
||||
//! @author Andrew Schwartzmeyer <andschwa@microsoft.com>
|
||||
//! @brief Tests GetFileOwner
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#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);
|
||||
}
|
||||
@@ -3,38 +3,35 @@
|
||||
//! @brief Unit tests for GetFullyQualifiedName
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "getcomputername.h"
|
||||
#include "getfullyqualifiedname.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <string>
|
||||
|
||||
//! 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
//! @file test-getuserfrompid.cpp
|
||||
//! @author Andrew Schwartzmeyer <andschwa@microsoft.com>
|
||||
//! @brief Unit tests for GetUserFromPid
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <pwd.h>
|
||||
#include "getuserfrompid.h"
|
||||
|
||||
TEST(GetUserFromPid, Success)
|
||||
{
|
||||
char* expected = getpwuid(geteuid())->pw_name;
|
||||
EXPECT_STREQ(GetUserFromPid(getpid()), expected);
|
||||
}
|
||||
@@ -2,9 +2,6 @@
|
||||
//! @author Andrew Schwartzmeyer <andschwa@microsoft.com>
|
||||
//! @brief Unit tests for GetUserName
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unistd.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <pwd.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
@@ -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'
|
||||
|
||||
Reference in New Issue
Block a user