コード例 #1
0
        private static unsafe bool TryGetUserNameFromPasswd(byte *buf, int bufLen, out string path)
        {
            // Call getpwuid_r to get the passwd struct
            Interop.Sys.Passwd passwd;
            int error = Interop.Sys.GetPwUidR(Interop.Sys.GetEUid(), out passwd, buf, bufLen);

            // If the call succeeds, give back the user name retrieved
            if (error == 0)
            {
                Debug.Assert(passwd.Name != null);
                path = Marshal.PtrToStringAnsi((IntPtr)passwd.Name);
                return(true);
            }

            // If the current user's entry could not be found, give back null,
            // but still return true as false indicates the buffer was too small.
            if (error == -1)
            {
                path = null;
                return(true);
            }

            var errorInfo = new Interop.ErrorInfo(error);

            // If the call failed because the buffer was too small, return false to
            // indicate the caller should try again with a larger buffer.
            if (errorInfo.Error == Interop.Error.ERANGE)
            {
                path = null;
                return(false);
            }

            // Otherwise, fail.
            throw new IOException(errorInfo.GetErrorMessage(), errorInfo.RawErrno);
        }
コード例 #2
0
    internal static Exception GetIOException(Interop.ErrorInfo errorInfo, string?path = null)
    {
        string msg = errorInfo.GetErrorMessage();

        return(new IOException(
                   string.IsNullOrEmpty(path) ? msg : $"{msg} : '{path}'", errorInfo.RawErrno));
    }
コード例 #3
0
        private static unsafe bool TryGetPasswd(string name, byte *buf, int bufLen, out Interop.Sys.Passwd?passwd)
        {
            // Call getpwnam_r to get the passwd struct
            Interop.Sys.Passwd tempPasswd;
            int error = Interop.Sys.GetPwNamR(name, out tempPasswd, buf, bufLen);

            // If the call succeeds, give back the passwd retrieved
            if (error == 0)
            {
                passwd = tempPasswd;
                return(true);
            }

            // If the current user's entry could not be found, give back null,
            // but still return true as false indicates the buffer was too small.
            if (error == -1)
            {
                passwd = null;
                return(true);
            }

            var errorInfo = new Interop.ErrorInfo(error);

            // If the call failed because the buffer was too small, return false to
            // indicate the caller should try again with a larger buffer.
            if (errorInfo.Error == Interop.Error.ERANGE)
            {
                passwd = null;
                return(false);
            }

            // Otherwise, fail.
            throw new Win32Exception(errorInfo.RawErrno, errorInfo.GetErrorMessage());
        }
コード例 #4
0
ファイル: SecureString.Unix.cs プロジェクト: ikopylov/corefx
 private static Exception CreateExceptionFromErrno()
 {
     Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo();
     return((errorInfo.Error == Interop.Error.ENOMEM || errorInfo.Error == Interop.Error.EPERM) ?
            (Exception) new OutOfMemoryException(SR.OutOfMemory_MemoryResourceLimits) :
            (Exception) new InvalidOperationException(errorInfo.GetErrorMessage()));
 }
コード例 #5
0
        /// <summary>Invoke <see cref="Interop.Sys.SysConf"/>, throwing if it fails.</summary>
        private static int CheckedSysConf(Interop.Sys.SysConfName name)
        {
            long result = Interop.Sys.SysConf(name);

            if (result == -1)
            {
                Interop.ErrorInfo errno = Interop.Sys.GetLastErrorInfo();
                throw errno.Error == Interop.Error.EINVAL ?
                      new ArgumentOutOfRangeException(nameof(name), name, errno.GetErrorMessage()) :
                      Interop.GetIOException(errno);
            }
            return((int)result);
        }
コード例 #6
0
        /// <summary>
        /// Checks the file has the correct permissions and attempts to modify them if they're inappropriate.
        /// </summary>
        /// <param name="stream">
        /// The file stream to check.
        /// </param>
        /// <param name="userId">
        /// The current userId from GetEUid().
        /// </param>
        private static void EnsureFilePermissions(FileStream stream, uint userId)
        {
            // Verify that we're creating files with u+rw and g-rw, o-rw.
            const Interop.Sys.Permissions requiredPermissions =
                Interop.Sys.Permissions.S_IRUSR | Interop.Sys.Permissions.S_IWUSR;

            const Interop.Sys.Permissions forbiddenPermissions =
                Interop.Sys.Permissions.S_IRGRP | Interop.Sys.Permissions.S_IWGRP |
                Interop.Sys.Permissions.S_IROTH | Interop.Sys.Permissions.S_IWOTH;

            Interop.Sys.FileStatus stat;
            if (Interop.Sys.FStat(stream.SafeFileHandle, out stat) != 0)
            {
                Interop.ErrorInfo error = Interop.Sys.GetLastErrorInfo();
                throw new CryptographicException(
                          SR.Cryptography_FileStatusError,
                          new IOException(error.GetErrorMessage(), error.RawErrno));
            }

            if (stat.Uid != userId)
            {
                throw new CryptographicException(SR.Format(SR.Cryptography_OwnerNotCurrentUser, stream.Name));
            }

            if ((stat.Mode & (int)requiredPermissions) != (int)requiredPermissions ||
                (stat.Mode & (int)forbiddenPermissions) != 0)
            {
                if (Interop.Sys.FChMod(stream.SafeFileHandle, (int)requiredPermissions) < 0)
                {
                    Interop.ErrorInfo error = Interop.Sys.GetLastErrorInfo();
                    throw new CryptographicException(
                              SR.Format(SR.Cryptography_InvalidFilePermissions, stream.Name),
                              new IOException(error.GetErrorMessage(), error.RawErrno));
                }

                // Verify the chmod applied.
                if (Interop.Sys.FStat(stream.SafeFileHandle, out stat) != 0)
                {
                    Interop.ErrorInfo error = Interop.Sys.GetLastErrorInfo();
                    throw new CryptographicException(
                              SR.Cryptography_FileStatusError,
                              new IOException(error.GetErrorMessage(), error.RawErrno));
                }

                if ((stat.Mode & (int)requiredPermissions) != (int)requiredPermissions ||
                    (stat.Mode & (int)forbiddenPermissions) != 0)
                {
                    throw new CryptographicException(SR.Format(SR.Cryptography_InvalidFilePermissions, stream.Name));
                }
            }
        }
コード例 #7
0
        /// <summary>Wrapper for getpwuid_r.</summary>
        /// <param name="bufLen">The length of the buffer to use when storing the password result.</param>
        /// <param name="path">The resulting path; null if the user didn't have an entry.</param>
        /// <returns>true if the call was successful (path may still be null); false is a larger buffer is needed.</returns>
        private static bool TryGetHomeDirectoryFromPasswd(int bufLen, out string path)
        {
            // Call getpwuid_r to get the passwd struct
            Interop.Sys.Passwd passwd;
            IntPtr             buffer = Marshal.AllocHGlobal(bufLen);

            try
            {
                int error = Interop.Sys.GetPwUidR(Interop.Sys.GetEUid(), out passwd, buffer, bufLen);

                // If the call succeeds, give back the home directory path retrieved
                if (error == 0)
                {
                    Debug.Assert(passwd.HomeDirectory != IntPtr.Zero);
                    path = Marshal.PtrToStringAnsi(passwd.HomeDirectory);
                    return(true);
                }

                // If the current user's entry could not be found, give back null
                // path, but still return true as false indicates the buffer was
                // too small.
                if (error == -1)
                {
                    path = null;
                    return(true);
                }

                var errorInfo = new Interop.ErrorInfo(error);

                // If the call failed because the buffer was too small, return false to
                // indicate the caller should try again with a larger buffer.
                if (errorInfo.Error == Interop.Error.ERANGE)
                {
                    path = null;
                    return(false);
                }

                // Otherwise, fail.
                throw new IOException(errorInfo.GetErrorMessage(), errorInfo.RawErrno);
            }
            finally
            {
                // Deallocate the buffer we created
                Marshal.FreeHGlobal(buffer);
            }
        }
コード例 #8
0
        /// <summary>Wrapper for getpwuid_r.</summary>
        /// <param name="buf">The scratch buffer to pass into getpwuid_r.</param>
        /// <param name="bufLen">The length of <paramref name="buf"/>.</param>
        /// <param name="path">The resulting path; null if the user didn't have an entry.</param>
        /// <returns>true if the call was successful (path may still be null); false is a larger buffer is needed.</returns>
        private static unsafe bool TryGetHomeDirectoryFromPasswd(byte *buf, int bufLen, out string path)
        {
            while (true)
            {
                // Call getpwuid_r to get the passwd struct
                Interop.Sys.Passwd passwd;
                IntPtr             result;
                int rv = Interop.Sys.GetPwUid(Interop.Sys.GetEUid(), out passwd, buf, bufLen, out result);

                // If the call succeeds, give back the home directory path retrieved
                if (rv == 0)
                {
                    if (result == IntPtr.Zero)
                    {
                        // Current user's entry could not be found
                        path = null; // we'll still return true, as false indicates the buffer was too small
                    }
                    else
                    {
                        Debug.Assert(result == (IntPtr)(&passwd));
                        Debug.Assert(passwd.HomeDirectory != null);
                        path = Marshal.PtrToStringAnsi((IntPtr)passwd.HomeDirectory);
                    }
                    return(true);
                }

                // If the call failed because it was interrupted, try again.
                Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo();
                if (errorInfo.Error == Interop.Error.EINTR)
                {
                    continue;
                }

                // If the call failed because the buffer was too small, return false to
                // indicate the caller should try again with a larger buffer.
                if (errorInfo.Error == Interop.Error.ERANGE)
                {
                    path = null;
                    return(false);
                }

                // Otherwise, fail.
                throw new IOException(errorInfo.GetErrorMessage(), errorInfo.RawErrno);
            }
        }
コード例 #9
0
        /// <summary>
        /// Checks the file has the correct permissions.
        /// </summary>
        /// <param name="stream">
        /// The file stream to check.
        /// </param>
        /// <param name="userId">
        /// The current userId from GetEUid().
        /// </param>
        private static void EnsureFilePermissions(FileStream stream, uint userId)
        {
            // Verify that we're creating files with u+rw and o-rw, g-rw.
            const Interop.Sys.Permissions requiredPermissions =
                Interop.Sys.Permissions.S_IRUSR |
                Interop.Sys.Permissions.S_IWUSR;

            const Interop.Sys.Permissions forbiddenPermissions =
                Interop.Sys.Permissions.S_IROTH |
                Interop.Sys.Permissions.S_IWOTH |
                Interop.Sys.Permissions.S_IRGRP |
                Interop.Sys.Permissions.S_IWGRP;

            // NOTE: no need to call DangerousAddRef here, since the FileStream is
            // held open outside of this method
            int fileDescriptor = (int)stream.SafeFileHandle.DangerousGetHandle();

            Interop.Sys.FileStatus stat;
            if (Interop.Sys.FStat(fileDescriptor, out stat) != 0)
            {
                Interop.ErrorInfo error = Interop.Sys.GetLastErrorInfo();
                throw new CryptographicException(
                          SR.Cryptography_FileStatusError,
                          new IOException(error.GetErrorMessage(), error.RawErrno));
            }

            if (stat.Uid != userId)
            {
                throw new CryptographicException(SR.Format(SR.Cryptography_OwnerNotCurrentUser, stream.Name));
            }

            if ((stat.Mode & (int)requiredPermissions) != (int)requiredPermissions)
            {
                throw new CryptographicException(SR.Format(SR.Cryptography_InsufficientFilePermissions, stream.Name));
            }

            if ((stat.Mode & (int)forbiddenPermissions) != 0)
            {
                throw new CryptographicException(SR.Format(SR.Cryptography_TooBroadFilePermissions, stream.Name));
            }
        }
コード例 #10
0
        /// <summary>
        /// Checks the store directory has the correct permissions.
        /// </summary>
        /// <param name="path">
        /// The path of the directory to check.
        /// </param>
        /// <param name="userId">
        /// The current userId from GetEUid().
        /// </param>
        private static void EnsureDirectoryPermissions(string path, uint userId)
        {
            Interop.Sys.FileStatus dirStat;
            if (Interop.Sys.Stat(path, out dirStat) != 0)
            {
                Interop.ErrorInfo error = Interop.Sys.GetLastErrorInfo();
                throw new CryptographicException(
                          SR.Cryptography_FileStatusError,
                          new IOException(error.GetErrorMessage(), error.RawErrno));
            }

            if (dirStat.Uid != userId)
            {
                throw new CryptographicException(SR.Format(SR.Cryptography_OwnerNotCurrentUser, path));
            }

            if ((dirStat.Mode & (int)Interop.Sys.Permissions.S_IRWXU) != (int)Interop.Sys.Permissions.S_IRWXU)
            {
                throw new CryptographicException(SR.Format(SR.Cryptography_InvalidDirectoryPermissions, path));
            }
        }
コード例 #11
0
        /// <summary>
        /// Checks the store directory has the correct permissions.
        /// </summary>
        /// <param name="path">
        /// The path of the directory to check.
        /// </param>
        /// <param name="userId">
        /// The current userId from GetEUid().
        /// </param>
        private static void EnsureDirectoryPermissions(string path, uint userId)
        {
            Interop.Sys.FileStatus dirStat;
            if (Interop.Sys.Stat(path, out dirStat) != 0)
            {
                Interop.ErrorInfo error = Interop.Sys.GetLastErrorInfo();
                throw new CryptographicException(
                          SR.Cryptography_FileStatusError,
                          new IOException(error.GetErrorMessage(), error.RawErrno));
            }

            if (dirStat.Uid != userId)
            {
                throw new CryptographicException(SR.Format(SR.Cryptography_OwnerNotCurrentUser, path));
            }

            const UnixFileMode UserReadWriteExecute = UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute;
            UnixFileMode       permissions          = File.GetUnixFileMode(path);

            if ((permissions & UserReadWriteExecute) != UserReadWriteExecute)
            {
                throw new CryptographicException(SR.Format(SR.Cryptography_InvalidDirectoryPermissions, path));
            }
        }
コード例 #12
0
        /// <summary>Wrapper for getpwuid_r.</summary>
        /// <param name="buf">The scratch buffer to pass into getpwuid_r.</param>
        /// <param name="bufLen">The length of <paramref name="buf"/>.</param>
        /// <param name="path">The resulting path; null if the user didn't have an entry.</param>
        /// <returns>true if the call was successful (path may still be null); false is a larger buffer is needed.</returns>
        private static unsafe bool TryGetHomeDirectoryFromPasswd(byte* buf, int bufLen, out string path)
        {
            // Call getpwuid_r to get the passwd struct
            Interop.Sys.Passwd passwd;
            int error = Interop.Sys.GetPwUidR(Interop.Sys.GetEUid(), out passwd, buf, bufLen);

            // If the call succeeds, give back the home directory path retrieved
            if (error == 0)
            {
                Debug.Assert(passwd.HomeDirectory != null);
                path = Marshal.PtrToStringAnsi((IntPtr)passwd.HomeDirectory);
                return true;
            }

            // If the current user's entry could not be found, give back null
            // path, but still return true as false indicates the buffer was
            // too small.
            if (error == -1)
            {
                path = null;
                return true;
            }

            var errorInfo = new Interop.ErrorInfo(error);

            // If the call failed because the buffer was too small, return false to 
            // indicate the caller should try again with a larger buffer.
            if (errorInfo.Error == Interop.Error.ERANGE)
            {
                path = null;
                return false;
            }

            // Otherwise, fail.
            throw new IOException(errorInfo.GetErrorMessage(), errorInfo.RawErrno);
        }
コード例 #13
0
        private bool ForkAndExecProcess(
            ProcessStartInfo startInfo, string?resolvedFilename, string[] argv,
            string[] envp, string?cwd, bool setCredentials, uint userId,
            uint groupId, uint[]?groups,
            out int stdinFd, out int stdoutFd, out int stderrFd,
            bool usesTerminal, bool throwOnNoExec = true)
        {
            if (string.IsNullOrEmpty(resolvedFilename))
            {
                Interop.ErrorInfo errno = Interop.Error.ENOENT.Info();
                throw CreateExceptionForErrorStartingProcess(errno.GetErrorMessage(), errno.RawErrno, startInfo.FileName, cwd);
            }

            // Lock to avoid races with OnSigChild
            // By using a ReaderWriterLock we allow multiple processes to start concurrently.
            s_processStartLock.EnterReadLock();
            try
            {
                if (usesTerminal)
                {
                    ConfigureTerminalForChildProcesses(1);
                }

                int childPid;

                // Invoke the shim fork/execve routine.  It will create pipes for all requested
                // redirects, fork a child process, map the pipe ends onto the appropriate stdin/stdout/stderr
                // descriptors, and execve to execute the requested process.  The shim implementation
                // is used to fork/execve as executing managed code in a forked process is not safe (only
                // the calling thread will transfer, thread IDs aren't stable across the fork, etc.)
                int errno = Interop.Sys.ForkAndExecProcess(
                    resolvedFilename, argv, envp, cwd,
                    startInfo.RedirectStandardInput, startInfo.RedirectStandardOutput, startInfo.RedirectStandardError,
                    setCredentials, userId, groupId, groups,
                    out childPid, out stdinFd, out stdoutFd, out stderrFd);

                if (errno == 0)
                {
                    // Ensure we'll reap this process.
                    // note: SetProcessId will set this if we don't set it first.
                    _waitStateHolder = new ProcessWaitState.Holder(childPid, isNewChild: true, usesTerminal);

                    // Store the child's information into this Process object.
                    Debug.Assert(childPid >= 0);
                    SetProcessId(childPid);
                    SetProcessHandle(new SafeProcessHandle(_processId, GetSafeWaitHandle()));

                    return(true);
                }
                else
                {
                    if (!throwOnNoExec &&
                        new Interop.ErrorInfo(errno).Error == Interop.Error.ENOEXEC)
                    {
                        return(false);
                    }

                    throw CreateExceptionForErrorStartingProcess(new Interop.ErrorInfo(errno).GetErrorMessage(), errno, resolvedFilename, cwd);
                }
            }
            finally
            {
                s_processStartLock.ExitReadLock();

                if (_waitStateHolder == null && usesTerminal)
                {
                    // We failed to launch a child that could use the terminal.
                    s_processStartLock.EnterWriteLock();
                    ConfigureTerminalForChildProcesses(-1);
                    s_processStartLock.ExitWriteLock();
                }
            }
        }
コード例 #14
0
 internal static Exception GetIOException(Interop.ErrorInfo errorInfo)
 {
     return(new IOException(errorInfo.GetErrorMessage(), errorInfo.RawErrno));
 }