Mbrd_UserGroup.cpp [plain text]
#include "Mbrd_UserGroup.h"
#include <mach/mach_time.h>
#include <pthread.h>
#include <stdlib.h>
#include <uuid/uuid.h>
#include <DirectoryServiceCore/CLog.h>
static long double gScaleNumerator = 0.0;
static long double gScaleDenominator = 0.0;
static pthread_once_t gInitializeTimebase = PTHREAD_ONCE_INIT;
static void InitializeTimebase( void )
{
struct mach_timebase_info mti = { 0 };
mach_timebase_info( &mti );
gScaleNumerator = (long double) mti.numer;
gScaleDenominator = (long double) mti.denom;
}
uint32_t GetElapsedSeconds( void )
{
pthread_once( &gInitializeTimebase, InitializeTimebase );
long double elapsed = (long double) mach_absolute_time();
long double temp = (elapsed * gScaleNumerator) / gScaleDenominator;
return (uint32_t) (temp / (long double) NSEC_PER_SEC);
}
uint64_t GetElapsedMicroSeconds( void )
{
pthread_once( &gInitializeTimebase, InitializeTimebase );
long double elapsed = (long double) mach_absolute_time();
long double temp = (elapsed * gScaleNumerator) / gScaleDenominator;
return (uint64_t) (temp / (long double) NSEC_PER_USEC);
}
#pragma mark -
#pragma mark UserGroup routines
UserGroup* UserGroup_Create( void )
{
UserGroup* result = (UserGroup *) calloc( 1, sizeof(UserGroup) );
assert( result != NULL );
result->fMagic = 'free';
result->fRefCount = 1;
UserGroup_Initialize( result );
return result;
}
void UserGroup_Initialize( UserGroup *source )
{
pthread_mutexattr_t attr;
if ( source->fMagic != 'free' ) {
bzero( source, sizeof(UserGroup) );
source->fRefCount = INT32_MAX;
}
assert( pthread_mutexattr_init(&attr) == 0 );
assert( pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK) == 0 );
assert( pthread_mutex_init(&source->fMutex, &attr) == 0 );
assert( pthread_mutex_init(&source->fHashLock, &attr) == 0 );
pthread_mutexattr_destroy( &attr );
source->fNodeAvailable = true;
source->fID = -1; source->fPrimaryGroup = -1; source->fTimestamp = time( NULL );
source->fQueue = dispatch_queue_create( "UserGroup queue", NULL );
source->fRefreshQueue = dispatch_queue_create( "UserGroup refresh queue", NULL );
HashTable_Initialize( &source->fGUIDMembershipHash, "GUID", source, eGUIDHash );
HashTable_Initialize( &source->fSIDMembershipHash, "SID", source, eSIDHash );
HashTable_Initialize( &source->fGIDMembershipHash, "GID", source, eIDHash );
}
void UserGroup_Release( UserGroup *source )
{
if ( dsReleaseObject(source, &source->fRefCount, false) == true ) {
UserGroup_Free( source );
if ( source->fMagic == 'free' ) {
free( source );
}
}
}
void UserGroup_Free( UserGroup *source )
{
assert( pthread_mutex_lock(&source->fMutex) == 0 );
DSFree( source->fName );
DSFree( source->fNode );
for ( int ii = 0; ii < kMaxAltIdentities && source->fKerberos[ii] != NULL; ii++ ) {
DSFree( source->fKerberos[ii] );
}
for ( int ii = 0; ii < kMaxAltIdentities && source->fX509DN[ii] != NULL; ii++ ) {
DSFree( source->fX509DN[ii] );
}
dispatch_release( source->fQueue );
dispatch_release( source->fRefreshQueue );
HashTable_FreeContents( &source->fGUIDMembershipHash );
HashTable_FreeContents( &source->fSIDMembershipHash );
HashTable_FreeContents( &source->fGIDMembershipHash );
pthread_mutex_destroy( &source->fMutex );
pthread_mutex_destroy( &source->fHashLock );
}
void UserGroup_Merge( UserGroup *existing, UserGroup *source, bool includeMemberships )
{
assert( pthread_mutex_lock(&existing->fMutex) == 0 );
existing->fTimestamp = source->fTimestamp;
existing->fExpiration = source->fExpiration;
existing->fMaximumRefresh = source->fMaximumRefresh;
uuid_copy( existing->fGUID, source->fGUID );
existing->fID = source->fID;
existing->fPrimaryGroup = source->fPrimaryGroup;
if ( (source->fFlags & kUGFlagHasSID) != 0 ) {
bcopy( &source->fSID, &existing->fSID, sizeof(ntsid_t) );
}
else {
existing->fFlags &= ~kUGFlagHasSID;
}
if ( existing->fNode != NULL ) {
free( existing->fNode );
}
if ( source->fNode != NULL ) {
existing->fNode = strdup( source->fNode );
}
else {
existing->fNode = NULL;
}
existing->fToken = source->fToken;
existing->fNodeAvailable = source->fNodeAvailable;
if ( source->fName != NULL ) {
if ( existing->fName != NULL ) {
free( existing->fName );
}
existing->fName = strdup( source->fName );
}
if (source->fFlags & kUGFlagHasX509DN) {
for ( int ii = 0; ii < kMaxAltIdentities; ii++ ) {
DSFree( existing->fX509DN[ii] );
if ( source->fX509DN[ii] != NULL ) {
existing->fX509DN[ii] = strdup( source->fX509DN[ii] );
}
}
} else {
existing->fFlags &= ~kUGFlagHasX509DN;
}
if (source->fFlags & kUGFlagHasKerberos) {
for ( int ii = 0; ii < kMaxAltIdentities; ii++ ) {
DSFree( existing->fKerberos[ii] );
if ( source->fKerberos[ii] != NULL ) {
existing->fKerberos[ii] = strdup( source->fKerberos[ii] );
}
}
} else {
existing->fFlags &= ~kUGFlagHasKerberos;
}
existing->fRecordType = source->fRecordType;
existing->fFlags |= (source->fFlags & ~kUGFlagValidMembership);
existing->fFoundBy |= source->fFoundBy;
if ( includeMemberships == true && (source->fFlags & kUGFlagValidMembership) != 0 )
{
assert( pthread_mutex_lock(&existing->fHashLock) == 0 );
HashTable_Reset( &existing->fGUIDMembershipHash );
HashTable_Merge( &existing->fGUIDMembershipHash, &source->fGUIDMembershipHash );
HashTable_Reset( &existing->fSIDMembershipHash );
HashTable_Merge( &existing->fSIDMembershipHash, &source->fSIDMembershipHash );
HashTable_Reset( &existing->fGIDMembershipHash );
HashTable_Merge( &existing->fGIDMembershipHash, &source->fGIDMembershipHash );
assert( pthread_mutex_unlock(&existing->fHashLock) == 0 );
existing->fFlags |= kUGFlagValidMembership;
}
assert( pthread_mutex_unlock(&existing->fMutex) == 0 );
}
bool UserGroup_AddToHashes( UserGroup *item, UserGroup *group )
{
bool bSuccess = false;
assert( pthread_mutex_lock(&item->fHashLock) == 0 );
if ( item != NULL )
{
if ( (group->fFlags & kUGFlagHasGUID) != 0 )
bSuccess = HashTable_Add( &item->fGUIDMembershipHash, group, false );
if ( (group->fFlags & kUGFlagHasID) != 0 )
bSuccess = (HashTable_Add(&item->fGIDMembershipHash, group, false) ? true : bSuccess);
if ( (group->fFlags & kUGFlagHasSID) != 0 )
bSuccess = (HashTable_Add(&item->fSIDMembershipHash, group, false) ? true : bSuccess);
}
assert( pthread_mutex_unlock(&item->fHashLock) == 0 );
return bSuccess;
}
int UserGroup_ResetMemberships( UserGroup *ug )
{
int totalOffline = 0;
__sync_and_and_fetch( &ug->fFlags, ~kUGFlagValidMembership );
assert( pthread_mutex_lock(&ug->fHashLock) == 0 );
totalOffline += HashTable_ResetMemberships( &ug->fGUIDMembershipHash );
totalOffline += HashTable_ResetMemberships( &ug->fSIDMembershipHash );
totalOffline += HashTable_ResetMemberships( &ug->fGIDMembershipHash );
DbgLog( kLogInfo, "mbr_mig - Membership - User/Group - Reset Memberships for %s (%d) - %d offline memberships", ug->fName ? :"\"no name\"",
ug->fID, totalOffline );
assert( pthread_mutex_unlock(&ug->fHashLock) == 0 );
return totalOffline;
}
const char *UserGroup_GetRecordTypeString( UserGroup *user )
{
const char *type;
switch( user->fRecordType )
{
case kUGRecordTypeUser:
type = "User";
break;
case kUGRecordTypeGroup:
type = "Group";
break;
case kUGRecordTypeUser | kUGRecordTypeComputer:
type = "User/Computer";
break;
case kUGRecordTypeComputer:
type = "Computer";
break;
case kUGRecordTypeComputerGroup:
type = "ComputerGroup";
break;
case kUGRecordTypeGroup | kUGRecordTypeComputerGroup:
type = "Group/ComputerGroup";
break;
default:
type = "No record type";
break;
}
return type;
}
const char *UserGroup_GetFoundByString( UserGroup *user, char *buffer, size_t bufferLen )
{
bool bAddComma = false;
assert( buffer != NULL && bufferLen > 0 );
buffer[0] = '\0';
if ( (user->fFoundBy & kUGFoundByGUID) != 0 ) {
strlcat( buffer, "UUID", bufferLen );
bAddComma = true;
}
if ( (user->fFoundBy & kUGFoundByID) != 0 ) {
if ( bAddComma == true ) {
strlcat( buffer, ", ", bufferLen );
};
strlcat( buffer, "ID", bufferLen );
bAddComma = true;
}
if ( (user->fFoundBy & kUGFoundByName) != 0 ) {
if ( bAddComma == true ) {
strlcat( buffer, ", ", bufferLen );
};
strlcat( buffer, "Name", bufferLen );
bAddComma = true;
}
if ( (user->fFoundBy & kUGFoundBySID) != 0 ) {
if ( bAddComma == true ) {
strlcat( buffer, ", ", bufferLen );
};
strlcat( buffer, "SID", bufferLen );
bAddComma = true;
}
if ( (user->fFoundBy & kUGFoundByNestedGroup) != 0 ) {
if ( bAddComma == true ) {
strlcat( buffer, ", ", bufferLen );
};
strlcat( buffer, "Nested group search", bufferLen );
}
if ( (user->fFoundBy & kUGFoundByX509DN) != 0 ) {
if ( bAddComma == true ) {
strlcat( buffer, ", ", bufferLen );
};
strlcat( buffer, "X509DN", bufferLen );
}
if ( (user->fFoundBy & kUGFoundByKerberos) != 0 ) {
if ( bAddComma == true ) {
strlcat( buffer, ", ", bufferLen );
};
strlcat( buffer, "Kerberos ID", bufferLen );
}
if ( user->fFoundBy == 0 ) {
strlcat( buffer, "Unspecified", bufferLen );
}
return buffer;
}
int UserGroup_Get16Groups( UserGroup* user, gid_t* gidArray )
{
gid_t *tempArray = NULL;
int numGroups = UserGroup_GetGroups( user, &tempArray );
if ( numGroups > 16 ) numGroups = 16;
if ( numGroups > 0 ) {
bcopy( tempArray, gidArray, numGroups * sizeof(gid_t) );
free( tempArray );
}
return numGroups;
}
int UserGroup_GetGroups( UserGroup* user, gid_t** gidArray )
{
UserGroup **groupArray = NULL;
gid_t *itemArray = NULL;
int itemArrayCount = 0;
int i = 0;
gid_t pgid = -1;
if ( user == NULL || gidArray == NULL ) return 0;
int groupArrayCount = HashTable_CreateItemArray( &user->fGUIDMembershipHash, &groupArray );
if ( groupArrayCount > 0 )
{
(*gidArray) = itemArray = (gid_t *) calloc( groupArrayCount, sizeof(gid_t) );
assert( itemArray != NULL );
for ( i = 0; i < groupArrayCount; i++ )
{
gid_t tempGID = groupArray[i]->fID;
if ( tempGID != pgid ) {
itemArray[itemArrayCount++] = tempGID;
}
UserGroup_Release( groupArray[i] );
groupArray[i] = NULL;
}
if ( groupArray != NULL ) {
free( groupArray );
groupArray = NULL;
}
}
else {
(*gidArray) = itemArray = (gid_t *) calloc( 1, sizeof(gid_t) );
assert( itemArray != NULL );
itemArray[0] = user->fPrimaryGroup;
itemArrayCount = 1;
}
return itemArrayCount;
}