static PSECURITY_DESCRIPTOR s_GetFileSecurityDescriptor(const string& path) { if ( path.empty() ) { CNcbiError::Set(CNcbiError::eInvalidArgument); return NULL; } PSECURITY_DESCRIPTOR sd = NULL; DWORD size = 0; DWORD size_need = 0; if ( !GetFileSecurity(_T_XCSTRING(path), FILE_SECURITY_INFO, sd, size, &size_need) ) { if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { CNcbiError::SetFromWindowsError(); return NULL; } // Allocate memory for the buffer sd = (PSECURITY_DESCRIPTOR) LocalAlloc(LMEM_FIXED, size_need); if ( !sd ) { CNcbiError::SetFromWindowsError(); return NULL; } size = size_need; if ( !GetFileSecurity(_T_XCSTRING(path), FILE_SECURITY_INFO, sd, size, &size_need) ) { CNcbiError::SetFromWindowsError(); LocalFree((HLOCAL) sd); return NULL; } } return sd; }
void CInterProcessLock::Remove() { if (m_Handle != kInvalidLockHandle) { Unlock(); } NcbiSys_unlink(_T_XCSTRING(m_SystemName)); }
extern void DoThrowTraceAbort(void) { if ( !s_DTTA_Initialized ) { const TXChar* str = NcbiSys_getenv(_T_XCSTRING(ABORT_ON_THROW)); if (str && *str) s_DoThrowTraceAbort = true; s_DTTA_Initialized = true; } if ( s_DoThrowTraceAbort ) abort(); }
bool CWinSecurity::GetObjectOwner(const string& obj_name, SE_OBJECT_TYPE obj_type, string* owner, string* group, unsigned int* uid, unsigned int* gid) { PSID sid_owner; PSID sid_group; PSECURITY_DESCRIPTOR sd; DWORD res = GetNamedSecurityInfo(_T_XCSTRING(obj_name), obj_type, ACCOUNT_SECURITY_INFO, &sid_owner, &sid_group, NULL, NULL, &sd ); if ( res != ERROR_SUCCESS ) { CNcbiError::SetWindowsError(res); return false; } bool retval = s_GetOwnerGroupFromSIDs(sid_owner, sid_group, owner, group, uid, gid); LocalFree(sd); return retval; }
bool CWinSecurity::SetFileOwner(const string& filename, const string& owner, const string& group, unsigned int* uid, unsigned int* gid) { if ( uid ) *uid = 0; if ( gid ) *gid = 0; if ( owner.empty() && group.empty() ) { CNcbiError::Set(CNcbiError::eInvalidArgument); return false; } HANDLE token = INVALID_HANDLE_VALUE; PSID owner_sid = NULL; PSID group_sid = NULL; bool success = false; // Get SIDs for new owner and group if ( !owner.empty() ) { owner_sid = x_GetAccountSidByName(owner, SidTypeUser); if (!owner_sid) { return false; } } if ( !group.empty() ) { group_sid = x_GetAccountSidByName(group, SidTypeGroup); if (!group_sid) { goto cleanup; } } if (uid || gid) { s_GetOwnerGroupFromSIDs(owner_sid, group_sid, NULL, NULL, uid, gid); } // Change owner SECURITY_INFORMATION security_info = 0; if ( owner_sid ) { security_info |= OWNER_SECURITY_INFORMATION; } if ( group_sid ) { security_info |= GROUP_SECURITY_INFORMATION; } // Set new owner/group in the object's security descriptor if ( SetNamedSecurityInfo((TXChar*)_T_XCSTRING(filename), SE_FILE_OBJECT, security_info, owner_sid, group_sid, NULL, NULL) == ERROR_SUCCESS ) { success = true; goto cleanup; } // If the previous call failed because access was denied, // enable the necessary admin privileges for the current thread and try again. token = s_GetThreadToken(TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY); if ( token == INVALID_HANDLE_VALUE) { goto cleanup; } bool prev_ownership_name; bool prev_restore_name; if ( !SetTokenPrivilege(token, SE_TAKE_OWNERSHIP_NAME, true, &prev_ownership_name) || !SetTokenPrivilege(token, SE_RESTORE_NAME, true, &prev_restore_name) ) { goto cleanup; } if ( SetNamedSecurityInfo((TXChar*)_T_XCSTRING(filename), SE_FILE_OBJECT, security_info, owner_sid, group_sid, NULL, NULL) == ERROR_SUCCESS ) { success = true; } // Restore privileges SetTokenPrivilege(token, SE_TAKE_OWNERSHIP_NAME, prev_ownership_name); SetTokenPrivilege(token, SE_RESTORE_NAME, prev_restore_name); cleanup: if ( owner_sid ) LocalFree(owner_sid); if ( group_sid ) LocalFree(group_sid); if ( token != INVALID_HANDLE_VALUE) CloseHandle(token); return success; }
void CInterProcessLock::Lock(const CTimeout& timeout, const CTimeout& granularity) { CFastMutexGuard LOCK(s_ProcessLock); // Check that lock with specified name not already locked // in the current process. TLocks::iterator it = s_Locks->find(m_SystemName); if (m_Handle != kInvalidLockHandle) { // The lock is already set in this CInterProcessLock object, // just increase reference counter. _VERIFY(it != s_Locks->end()); it->second++; return; } else { if (it != s_Locks->end()) { // The lock already exists in the current process. // We can use one CInterProcessLock object with // multiple Lock() calls, but not with different // CInterProcessLock objects. For example, on MS-Windows, // we cannot wait on the same mutex in the same thread. // So, two different objects can set locks simultaneously. // And for OS-compatibility we can do nothing here, // except throwing an exception. NCBI_THROW(CInterProcessLockException, eMultipleLocks, "Attempt to lock already locked object " \ "in the same process"); } } // Try to acquire a lock with specified timeout #if defined(NCBI_OS_UNIX) // Open lock file mode_t perm = CDirEntry::MakeModeT( CDirEntry::fRead | CDirEntry::fWrite /* user */, CDirEntry::fRead | CDirEntry::fWrite /* group */, 0, 0 /* other & special */); int fd = open(m_SystemName.c_str(), O_CREAT | O_RDWR, perm); if (fd == -1) { NCBI_THROW(CInterProcessLockException, eCreateError, string("Error creating lockfile ") + m_SystemName + ": " + strerror(errno)); } // Try to acquire the lock int x_errno = 0; if (timeout.IsInfinite() || timeout.IsDefault()) { while ((x_errno = s_UnixLock(fd))) { if (errno != EAGAIN) break; } } else { unsigned long ms = timeout.GetAsMilliSeconds(); if ( !ms ) { // Timeout == 0 x_errno = s_UnixLock(fd); } else { // Timeout > 0 unsigned long ms_gran; if ( granularity.IsInfinite() || granularity.IsDefault() ) { ms_gran = min(ms/5, (unsigned long)500); } else { ms_gran = granularity.GetAsMilliSeconds(); } // Try to lock within specified timeout for (;;) { x_errno = s_UnixLock(fd); if ( !x_errno ) { // Successfully locked break; } if (x_errno != EACCES && x_errno != EAGAIN ) { // Error break; } // Otherwise -- sleep granularity timeout unsigned long ms_sleep = ms_gran; if (ms_sleep > ms) { ms_sleep = ms; } if ( !ms_sleep ) { break; } SleepMilliSec(ms_sleep); ms -= ms_sleep; } // Timeout if ( !ms ) { close(fd); NCBI_THROW(CInterProcessLockException, eLockTimeout, "The lock could not be acquired in the time " \ "allotted"); } } // if (!ms) } // if (timeout.IsInfinite()) // Error if ( x_errno ) { close(fd); NCBI_THROW(CInterProcessLockException, eLockError, "Error creating lock"); } // Success m_Handle = fd; #elif defined(NCBI_OS_MSWIN) HANDLE handle = ::CreateMutex(NULL, TRUE, _T_XCSTRING(m_SystemName)); errno_t errcode = ::GetLastError(); if (handle == kInvalidLockHandle) { switch(errcode) { case ERROR_ACCESS_DENIED: // Mutex with specified name already exists, // but we don't have enough rights to open it. NCBI_THROW(CInterProcessLockException, eLockError, "The lock already exists"); break; case ERROR_INVALID_HANDLE: // Some system object with the same name already exists NCBI_THROW(CInterProcessLockException, eLockError, "Error creating lock, system object with the same" \ "name already exists"); break; default: // Unknown error NCBI_THROW(CInterProcessLockException, eCreateError, "Error creating lock"); break; } } else { // Mutex with specified name already exists if (errcode == ERROR_ALREADY_EXISTS) { // Wait DWORD res; if (timeout.IsInfinite() || timeout.IsDefault()) { res = WaitForSingleObject(handle, INFINITE); } else { res = WaitForSingleObject(handle, timeout.GetAsMilliSeconds()); } switch(res) { case WAIT_OBJECT_0: // The lock has been acquired break; case WAIT_TIMEOUT: ::CloseHandle(handle); NCBI_THROW(CInterProcessLockException, eLockTimeout, "The lock could not be acquired in the time " \ "allotted"); break; case WAIT_ABANDONED: // The lock is in abandoned state... Other thread/process // owning it was terminated. We can reuse this mutex, but // it is better to wait until it will be released by OS. /* FALLTHRU */ default: ::CloseHandle(handle); NCBI_THROW(CInterProcessLockException, eLockError, "Error creating lock"); break; } } m_Handle = handle; } #endif // Set reference counter to 1 (*s_Locks)[m_SystemName] = 1; }