private byte[] LoadMasterKey() { var debug = "<unknown>"; try { if (_config.MasterKeyExec != null) { debug = _config.CertificateExec + " " + _config.CertificateExecArguments; return(LoadMasterKeyWithExecutable()); } if (_config.MasterKeyPath != null) { debug = _config.MasterKeyPath; return(LoadMasterKeyFromPath()); } if (PlatformDetails.RunningOnPosix == false) { return(null); } var dirpath = Path.Combine(Environment.GetEnvironmentVariable("HOME"), ".ravendb"); dirpath = Path.GetFullPath(dirpath); var filepath = Path.Combine(dirpath, "secret.key"); debug = filepath; var buffer = new byte[KeySize]; fixed(byte *pBuf = buffer) { if (Directory.Exists(dirpath) == false) { Directory.CreateDirectory(dirpath); } var fd = Syscall.open(filepath, PerPlatformValues.OpenFlags.O_CREAT | OpenFlags.O_RDWR, // octal 01600 - Sticky and only user can read it FilePermissions.S_ISVTX | FilePermissions.S_IRUSR | FilePermissions.S_IWUSR); if (fd == -1) { var err = Marshal.GetLastWin32Error(); Syscall.ThrowLastError(err, $"when opening {filepath}"); } try { var ret = Syscall.flock(fd, Syscall.FLockOperations.LOCK_EX); if (ret != 0) { var err = Marshal.GetLastWin32Error(); Syscall.ThrowLastError(err, $"could not lock {filepath}"); } var size = Syscall.lseek64(fd, 0, WhenceFlags.SEEK_END); if (size == -1) { var err = Marshal.GetLastWin32Error(); Syscall.ThrowLastError(err, $"could not get size of {filepath}"); } if (size == KeySize) { byte *pos = pBuf; long amountRead = 0; while (amountRead < KeySize) { var read = Syscall.pread(fd, pos, (ulong)(KeySize - amountRead), amountRead); pos += read; if (read < 0) { var err = Marshal.GetLastWin32Error(); Syscall.ThrowLastError(err, $"failed to read {filepath}"); } if (read == 0) { break; } amountRead += read; } if (amountRead != KeySize) { throw new FileLoadException($"Failed to read the full key size from {filepath}, expected to read {KeySize} but go only {amountRead}"); } } else // we assume that if the size isn't a key size, then it was never valid and regenerate the key { Sodium.randombytes_buf(pBuf, (UIntPtr)KeySize); if (Syscall.ftruncate(fd, IntPtr.Zero) != 0) { var err = Marshal.GetLastWin32Error(); Syscall.ThrowLastError(err, $"Failed to truncate {filepath}"); } if (Syscall.lseek64(fd, 0, WhenceFlags.SEEK_SET) == -1) { var err = Marshal.GetLastWin32Error(); Syscall.ThrowLastError(err, $"Failed to seek to beginning of {filepath}"); } var len = KeySize; while (len > 0) { var writeAmount = Syscall.write(fd, pBuf, KeySize); if (writeAmount <= 0) // 0 will be considered as error here { var err = Marshal.GetLastWin32Error(); Syscall.ThrowLastError(err, $"Failed to write {KeySize} bytes into {filepath}, only wrote {len}"); } len -= (int)writeAmount; } if (Syscall.FSync(fd) != 0) { var err = Marshal.GetLastWin32Error(); Syscall.ThrowLastError(err, $"Failed to FSync {filepath}"); } Syscall.FsyncDirectoryFor(filepath); } } finally { if (Syscall.close(fd) != 0) { var err = Marshal.GetLastWin32Error(); Syscall.ThrowLastError(err, $"Failed to close the secret key file : {filepath}"); } } return(buffer); } } catch (Exception e) { throw new CryptographicException( $"Unable to open the master secret key ({debug}), won't proceed because losing this key will lose access to all user encrypted information. Admin assistance required.", e); } }