#include #include #include #include #include uint32_t gTestCase = 0; bool gLogErrors = false; bool gVerbose = false; char *gLogPath = NULL; char *gAdminAccount = NULL; char *gAdminPassword = NULL; char *gProxyHost = NULL; char *gProxyPassword = NULL; char *gProxyUser = NULL; uint32_t gTestTimes = 1; uint32_t gCopies = 1; void usage( char *argv[] ) { fprintf( stderr, "Usage: TestAppCF -a adminPass -p adminPass [-v] [-e] [-l path] [-N runNumber]\n", argv[0] ); fprintf( stderr, " [-c copies] [-t times] [-u proxyUser -P proxyPass -h proxyHost]\n" ); fprintf( stderr, " -v verbose output\n" ); fprintf( stderr, " -e output error log\n" ); fprintf( stderr, " -l log path (default \"./Logs//\"\n" ); fprintf( stderr, " -N test run number\n" ); fprintf( stderr, " -c number of copies to fork for stress testing\n" ); fprintf( stderr, " -t number of times to run the test\n" ); fprintf( stderr, " -u Proxy username\n" ); fprintf( stderr, " -P Proxy username password\n" ); fprintf( stderr, " -h Proxy host\n" ); fprintf( stderr, " -a local admin account\n" ); fprintf( stderr, " -p local admin password\n" ); } void parseOptions( int argc, char *argv[] ) { int ch; gTestCase = (uint32_t) CFAbsoluteTimeGetCurrent(); while ((ch = getopt(argc, argv, "vel:N:c:t:u:P:h:a:p:")) != -1) { switch (ch) { case 'v': gVerbose = true; break; case 'e': gLogErrors = true; break; case 'l': gLogPath = optarg; break; case 'N': gTestCase = strtol( optarg, NULL, 10 ); break; case 'c': if( NULL != optarg ) { gCopies = strtol( optarg, NULL, 10 ); if( gCopies > 1024 ) gCopies = 1024; } else usage( argv ); break; case 't': if( NULL != optarg ) { gTestTimes = strtol( optarg, NULL, 10 ); if( 0 == gTestTimes ) gTestTimes = 1; } else usage( argv ); break; case 'u': // proxy user gProxyUser = optarg; break; case 'P': // proxy password gProxyPassword = optarg; break; case 'h': // host gProxyHost = optarg; break; case 'a': // admin gAdminAccount = optarg; break; case 'p': // local admin password gAdminPassword = optarg; break; case '?': default: usage( argv ); exit(1); } } if( NULL == gAdminAccount || NULL == gAdminPassword ) { usage( argv ); exit( 1 ); } else if( NULL != gProxyHost || NULL != gProxyUser || NULL != gProxyHost ) { if( NULL == gProxyHost || NULL == gProxyUser || NULL == gProxyHost ) { usage( argv ); exit( 1 ); } } } void searchCallback( ODContextRef inContext, CFMutableArrayRef inResults, CFErrorRef inResultCode ) { if( NULL != inResults ) { printf( "Got %d results\n", (int) CFArrayGetCount(inResults) ); } else { printf( "Got no more results\n" ); } } bool doTestMembership( ODNodeRef inNodeRef, ODRecordType inGroupType, ODRecordType inMemberType ) { CFErrorRef error = NULL; ODRecordRef testmember = NULL; ODRecordRef testcontainer = NULL; bool bReturn = false; CFArrayRef emptyValue = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks ); bool (^testFailure)( bool, const char *, CFErrorRef *) = ^( bool bSuccess, const char *testCase, CFErrorRef *inError ) { bool bFailed = true; CFErrorRef theError = (*inError); if ( theError != NULL ) { if ( bSuccess == false ) { printf( "%s - FAIL", testCase ); } else { printf( "%s - FAIL (error but status says success)", testCase ); } CFStringRef errorDesc = CFErrorCopyDescription( theError ); const char *errorStr = "no error details"; char buffer[512]; if ( errorDesc != NULL ) { CFStringGetCString( errorDesc, buffer, sizeof(buffer), kCFStringEncodingUTF8 ); errorStr = buffer; } printf( " - (%d) - %s\n", (int) CFErrorGetCode(theError), errorStr ); } else { if ( bSuccess == false ) { printf( "%s - FAIL - failed but no Error\n", testCase ); } else { printf( "%s - SUCCESS\n", testCase ); bFailed = false; } } return bFailed; }; char groupType[64]; char memberType[64]; CFStringGetCString( inGroupType, groupType, sizeof(groupType), kCFStringEncodingUTF8 ); if ( inMemberType != NULL ) { CFStringGetCString( inMemberType, memberType, sizeof(memberType), kCFStringEncodingUTF8 ); printf( "\n-- Container '%s' - Member '%s'\n", groupType, memberType ); testmember = ODNodeCreateRecord( inNodeRef, inMemberType, CFSTR("testmember"), NULL, &error ); if ( testFailure(testmember != NULL, "ODNodeCreateRecord 'testmember'", &error) == true ) { goto fail; } } else { printf( "\n-- Container '%s' - Member 'NULL'\n", groupType ); } testcontainer = ODNodeCreateRecord( inNodeRef, inGroupType, CFSTR("testcontainer"), NULL, &error ); if ( testFailure(testcontainer != NULL, "ODNodeCreateRecord 'testcontainer'", &error) == true ) { goto fail; } if ( inMemberType == NULL ) { if ( ODRecordAddMember(testcontainer, NULL, &error) == true ) { printf( "ODRecordAddMember (add NULL member) - FAIL (succeeded)\n" ); } else { printf( "ODRecordAddMember (add NULL member) - SUCCESS (got error)\n" ); } goto finish; } bool (^badMixture)( void ) = ^(void) { if ( (inGroupType == kODRecordTypeGroups && (inMemberType == kODRecordTypeUsers || inMemberType == kODRecordTypeGroups)) || (inGroupType == kODRecordTypeComputerGroups && (inMemberType == kODRecordTypeComputers || inMemberType == kODRecordTypeComputerGroups)) || (inGroupType == kODRecordTypeComputerLists && (inMemberType == kODRecordTypeComputers || inMemberType == kODRecordTypeComputerLists)) ) { return (bool) false; } return (bool) true; }; bool (^addMember)(const char *) = ^(const char *testCase) { char errorStr[256]; CFErrorRef localErr = NULL; snprintf( errorStr, sizeof(errorStr), "ODRecordAddMember (%s)", testCase ); if ( ODRecordAddMember(testcontainer, testmember, &localErr) == false ) { // need to check types, may expected failure if ( badMixture() == false ) { if ( testFailure(false, errorStr, &localErr) == true ) { return (bool) false; } } else { printf( "%s - SUCCESS (got error)\n", errorStr ); CFRelease( localErr ); localErr = NULL; } } else { printf( "%s - SUCCESS\n", errorStr ); } return (bool) true; }; // // add member with valid UUID if ( addMember("has UUID") == false ) goto fail; // // add member without UUID nor UID if ( testFailure(ODRecordSetValue(testmember, kODAttributeTypeGUID, emptyValue, &error), "ODRecordSetValue testmember (remove GUID)", &error) == true ) { goto fail; } // can only do this test if we are users cause group-in-group requires UUID or GID if ( inMemberType == kODRecordTypeUsers && addMember("no UUID nor UID/GID, if applicable") == false ) goto fail; ODAttributeType idAttr = NULL; if ( inMemberType == kODRecordTypeUsers ) { idAttr = kODAttributeTypeUniqueID; } else if ( inMemberType == kODRecordTypeGroups ) { idAttr = kODAttributeTypePrimaryGroupID; } if ( idAttr != NULL ) { // // set ID so we have a synthetic UUID if ( testFailure(ODRecordSetValue(testmember, idAttr, CFSTR("199"), &error), "ODRecordSetValue testmember (set UID)", &error) == true ) { goto fail; } if ( addMember("synthetic UUID") == false ) goto fail; } ODAttributeType mbrAttrib = NULL; ODAttributeType clearAttrib = NULL; if ( inMemberType == kODRecordTypeUsers || inMemberType == kODRecordTypeComputers ) { if ( inGroupType == kODRecordTypeComputerLists ) mbrAttrib = kODAttributeTypeComputers; else mbrAttrib = kODAttributeTypeGroupMembers; } else if ( inMemberType == kODRecordTypeGroups || inMemberType == kODRecordTypeComputerGroups ) { mbrAttrib = kODAttributeTypeNestedGroups; } else if ( inMemberType == kODRecordTypeComputerLists ) { mbrAttrib = kODAttributeTypeGroup; } else { goto finish; } if ( testFailure(ODRecordSetValue(testmember, kODAttributeTypeGUID, CFSTR("12345678-1234-1234-123456789011"), &error), "ODRecordSetValue testmember (put a UUID back)", &error) == true ) { goto fail; } // now add to fake GUIDs CFTypeRef values[] = { CFSTR("12345678-1234-1234-123456789012"), CFSTR("12345678-1234-1234-123456789013"), CFSTR("12345678-1234-1234-123456789014") }; CFArrayRef cfGUIDList = CFArrayCreate( kCFAllocatorDefault, values, sizeof(values) / sizeof(CFTypeRef), &kCFTypeArrayCallBacks ); if ( testFailure(ODRecordSetValue(testcontainer, mbrAttrib, cfGUIDList, &error), "ODRecordSetValue testcontainer (adding fake values)", &error) == true ) { goto fail; } if ( inGroupType == kODRecordTypeGroups && inMemberType == kODRecordTypeUsers && testFailure(ODRecordSetValue(testcontainer, kODAttributeTypeGroupMembership, emptyValue, &error), "ODRecordSetValue testcontainer (removing name list)", &error) == true ) { goto fail; } if ( addMember("adding member (missing legacy membership, if applicable)") == false ) goto fail; else if ( badMixture() == true ){ printf( "Stopping test because incompatible mix to do addition validation\n" ); goto finish; } CFArrayRef groupMembers = ODRecordCopyValues( testcontainer, mbrAttrib, &error ); if ( testFailure(groupMembers != NULL, "ODRecordCopyValues testcontainer", &error) == true ) { goto fail; } // should have 4 members now CFIndex count = CFArrayGetCount( groupMembers ); printf( "ODRecordCopyValues testcontainer (expected 4 got %d) - %s\n", (int) count, (count == 4 ? "SUCCESS" : "FAIL") ); if ( count != 4 ) { goto fail; } if ( addMember("adding member (twice)") == false ) goto fail; groupMembers = ODRecordCopyValues( testcontainer, mbrAttrib, &error ); if ( testFailure(groupMembers != NULL, "ODRecordCopyValues testcontainer", &error) == true ) { goto fail; } // should still have 4 members count = CFArrayGetCount( groupMembers ); printf( "ODRecordCopyValues testcontainer (expected 4 got %d) - %s\n", (int) count, (count == 4 ? "SUCCESS" : "FAIL") ); if ( count != 4 ) goto fail; // TODO: do we need to care about the name membership count? finish: bReturn = true; fail: ODRecordDelete( testmember, NULL ); ODRecordDelete( testcontainer, NULL ); return bReturn; }; void *doTest( void *inData ) { ODSessionRef cfRef = NULL; ODContextRef cfContext = 0; ODQueryRef cfQuery = NULL; CFArrayRef cfResults = NULL; CFStringRef cfProxyHost = NULL; CFStringRef cfProxyUser = NULL; CFStringRef cfProxyPassword = NULL; int ii; CFErrorRef cfError; ODNodeRef cfNodeRef = NULL; ODNodeRef cfLocalNodeRef = (ODNodeRef) inData; CFStringRef cfRecordName = CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR("TestCFFramework%ld"), (long) pthread_self() ); CFStringRef cfGroupName = CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR("TestGroup%ld"), (long) pthread_self() ); CFStringRef cfAddRecordName = CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR("TestAddRecord%ld"), (long) pthread_self() ); CFStringRef cfAddRecordAlias = CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR("TestAddRecordAlias%ld"), (long) pthread_self() ); if( NULL != gProxyHost ) { cfProxyHost = CFStringCreateWithCString( kCFAllocatorDefault, gProxyHost, kCFStringEncodingUTF8 ); cfProxyUser = CFStringCreateWithCString( kCFAllocatorDefault, gProxyUser, kCFStringEncodingUTF8 ); cfProxyPassword = CFStringCreateWithCString( kCFAllocatorDefault, gProxyPassword, kCFStringEncodingUTF8 ); } CFStringRef cfAdminAccount = CFStringCreateWithCString( kCFAllocatorDefault, gAdminAccount, kCFStringEncodingUTF8 ); CFStringRef cfAdminPassword = CFStringCreateWithCString( kCFAllocatorDefault, gAdminPassword, kCFStringEncodingUTF8 ); for( ii = 0; ii < gTestTimes; ii++ ) { // test all of the APIs if( NULL != gProxyHost ) { CFMutableDictionaryRef cfOptions = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); CFDictionarySetValue( cfOptions, kODSessionProxyAddress, cfProxyHost ); CFDictionarySetValue( cfOptions, kODSessionProxyUsername, cfProxyUser ); CFDictionarySetValue( cfOptions, kODSessionProxyPassword, cfProxyPassword ); cfRef = ODSessionCreate( kCFAllocatorDefault, cfOptions, NULL ); if( NULL != cfRef ) { printf("ODSessionCreate (with options) proxy - PASS\n"); CFRelease( cfRef ); cfRef = NULL; } else { printf( "ODSessionCreate (with options) proxy - FAIL\n" ); } CFRelease( cfOptions ); } else { printf("ODSessionCreate (with options) proxy - SKIP\n"); } cfRef = ODSessionCreate( kCFAllocatorDefault, NULL, NULL ); if( NULL != cfRef ) { printf( "ODSessionCreate - PASS\n" ); CFRelease( cfRef ); cfRef = NULL; } cfNodeRef = ODNodeCreateWithNodeType( kCFAllocatorDefault, kODSessionDefault, kODNodeTypeAuthentication, &cfError ); if( NULL != cfNodeRef ) { printf( "ODNodeCreate - PASS\n" ); CFArrayRef cfNodes = ODNodeCopySubnodeNames( cfNodeRef, NULL ); if( NULL != cfNodes ) { printf( "ODNodeCopySubnodeNames (Auth search node) - PASS\n" ); CFArrayRef cfUnreachable = ODNodeCopyUnreachableSubnodeNames( cfNodeRef, NULL ); if ( cfUnreachable != NULL ) { printf( "ODNodeCopyUnreachableSubnodeNames - FAIL - returned %d\n", (int) CFArrayGetCount(cfUnreachable) ); CFRelease( cfUnreachable ); cfUnreachable = NULL; } else { printf( "ODNodeCopyUnreachableSubnodeNames - PASS\n" ); } CFRelease( cfNodes ); cfNodes = NULL; } else { printf( "ODNodeCopySubnodeNames (Auth search node) - FAIL\n" ); } CFRelease( cfNodeRef ); cfNodeRef = NULL; } else { printf( "ODNodeCreateWithNodeType with kODTypeAuthenticationSearchNode - FAIL (%d)\n", (int) CFErrorGetCode(cfError) ); CFRelease( cfError ); } cfNodeRef = ODNodeCreateWithName( kCFAllocatorDefault, kODSessionDefault, CFSTR("/LDAPv3/od.apple.com"), &cfError ); if( NULL != cfNodeRef ) { printf( "ODNodeCreateWithName with /LDAPv3/od.apple.com - PASS\n" ); ODNodeRef cfNodeRef2 = ODNodeCreateCopy( kCFAllocatorDefault, cfNodeRef, NULL ); if( NULL != cfNodeRef2 ) { printf( "ODNodeCreateCopy - PASS\n" ); CFRelease( cfNodeRef2 ); cfNodeRef2 = NULL; } else { printf( "ODNodeCreateCopy - FAIL\n" ); } CFRelease( cfNodeRef ); cfNodeRef = NULL; } else { printf( "ODNodeCreateWithName with /LDAPv3/od.apple.com - FAIL (%d)\n", (int) CFErrorGetCode(cfError) ); CFRelease( cfError ); } cfLocalNodeRef = ODNodeCreateWithNodeType( kCFAllocatorDefault, kODSessionDefault, kODNodeTypeLocalNodes, &cfError ); if( NULL != cfLocalNodeRef ) { CFTypeRef cfValues[] = { cfAdminAccount }; CFArrayRef cfSearchValue = CFArrayCreate( kCFAllocatorDefault, cfValues, 1, &kCFTypeArrayCallBacks ); printf( "ODNodeCreateWithNodeType with kODTypeLocalNode - PASS\n" ); cfQuery = ODQueryCreateWithNode( kCFAllocatorDefault, cfLocalNodeRef, CFSTR(kDSStdRecordTypeUsers), CFSTR(kDSNAttrRecordName), kODMatchEqualTo, cfSearchValue, NULL, 0, NULL ); if( NULL != cfQuery ) { printf( "ODQueryCreateWithNode - PASS\n" ); cfResults = ODQueryCopyResults( cfQuery, false, NULL ); if( NULL != cfResults ) { printf( "ODQueryCopyResults returned non-NULL - PASS\n" ); if( CFArrayGetCount( cfResults ) != 0 ) { printf( "ODQueryCopyResults returned results (%d) - PASS\n", (int) CFArrayGetCount(cfResults) ); } else { printf( "ODQueryCopyResults returned results - FAIL\n" ); } CFRelease( cfResults ); cfResults = NULL; } else { printf( "ODQueryCopyResults returned non-NULL - FAIL\n" ); } CFRelease( cfQuery ); cfQuery = NULL; } ODRecordRef cfRecord = ODNodeCopyRecord( cfLocalNodeRef, CFSTR(kDSStdRecordTypeUsers), cfAdminAccount, NULL, NULL ); if( NULL != cfRecord ) { printf( "ODNodeCopyRecord - PASS\n" ); CFDictionaryRef cfPolicy = ODRecordCopyPasswordPolicy( kCFAllocatorDefault, cfRecord, NULL ); if( NULL != cfPolicy ) { printf( "ODNodeCopyUserPolicy - PASS\n" ); CFRelease( cfPolicy ); cfPolicy = NULL; } else { printf( "ODNodeCopyUserPolicy - FAIL\n" ); } if( ODRecordVerifyPassword(cfRecord, cfAdminPassword, NULL) == true ) { printf( "ODNodeVerifyCredentials - PASS\n" ); } else { printf( "ODNodeVerifyCredentials - FAIL\n" ); } CFStringRef cfAttribute = CFSTR(kDSAttributesAll); CFArrayRef cfAttribs = CFArrayCreate( kCFAllocatorDefault, (const void **) &cfAttribute, 1, &kCFTypeArrayCallBacks ); CFDictionaryRef cfValues = ODRecordCopyDetails( cfRecord, cfAttribs, NULL ); if( NULL != cfValues ) { printf( "ODRecordCopyDetails (kDSAttributesAll) - non-NULL - PASS\n" ); if( CFDictionaryGetCount(cfValues) != 0 ) { printf( "ODRecordCopyDetails (kDSAttributesAll) - has values - PASS\n" ); } else { printf( "ODRecordCopyDetails (kDSAttributesAll) - has values - FAIL\n" ); } CFRelease( cfValues ); cfValues = NULL; } else { printf( "ODRecordCopyAllAttributes - FAIL\n" ); } CFArrayRef cfAttribValues = ODRecordCopyValues( cfRecord, CFSTR(kDS1AttrNFSHomeDirectory), NULL ); if( NULL != cfAttribValues ) { printf( "ODRecordCopyValues - PASS\n" ); CFRelease( cfAttribValues ); cfAttribValues = NULL; } else { printf( "ODRecordCopyAttribute - FAIL\n" ); } #warning needs ODNodeAuthenticateExtended // dsStatus = ODNodeAuthenticateExtended( dsNodeRef, CFSTR(kDSStdRecordTypeUsers), CFSTR(), inAuthItems, // &outAuthItems, &dsContext ); // if( eDSNoErr == dsStatus ) // { // printf( "ODNodeAuthenticateExtended - PASS\n" ); // } // else // { // printf( "ODNodeAuthenticateExtended - FAIL\n" ); // } if( ODRecordSetNodeCredentials(cfRecord, cfAdminAccount, cfAdminPassword, NULL) ) { printf( "ODRecordSetNodeCredentials - PASS\n" ); } else { printf( "ODRecordSetNodeCredentials - FAIL\n" ); } } else { printf( "ODNodeCopyRecord - FAIL\n" ); } CFStringRef cfNodeName = ODNodeGetName( cfLocalNodeRef ); if( NULL != cfNodeName ) { printf( "ODNodeGetName - PASS\n" ); } else { printf( "ODNodeGetName - FAIL\n" ); } CFDictionaryRef cfNodeInfo = ODNodeCopyDetails( cfLocalNodeRef, NULL, NULL ); if( NULL != cfNodeInfo ) { printf( "ODNodeCopyDetails - PASS\n" ); CFRelease( cfNodeInfo ); cfNodeInfo = NULL; } else { printf( "ODNodeCopyDetails - FAIL\n" ); } CFArrayRef cfRecTypes = ODNodeCopySupportedRecordTypes( cfLocalNodeRef, NULL ); if( NULL != cfRecTypes ) { printf( "ODNodeCopySupportedRecordTypes - PASS\n" ); CFRelease( cfRecTypes ); cfRecTypes = NULL; } else { printf( "ODNodeCopySupportedRecordTypes - FAIL\n" ); } CFArrayRef cfAttribTypes = ODNodeCopySupportedAttributes( cfLocalNodeRef, NULL, NULL ); if( NULL != cfAttribTypes ) { printf( "ODNodeCopySupportedAttributes - PASS\n" ); CFRelease( cfAttribTypes ); cfAttribTypes = NULL; } else { printf( "ODNodeCopySupportedAttributes - FAIL\n" ); } if( ODNodeSetCredentials(cfLocalNodeRef, CFSTR(kDSStdRecordTypeUsers), cfAdminAccount, cfAdminPassword, NULL) ) { ODRecordRef cfRecord = NULL; printf( "ODNodeSetCredentials - PASS\n" ); cfRecord = ODNodeCreateRecord( cfLocalNodeRef, CFSTR(kDSStdRecordTypeUsers), cfRecordName, NULL, NULL ); if( NULL != cfRecord ) { printf( "ODNodeCreateRecord - PASS\n" ); ODRecordRef cfRecordTemp = ODNodeCreateRecord( cfLocalNodeRef, CFSTR(kDSStdRecordTypeUsers), cfRecordName, NULL, &cfError ); if( NULL != cfRecordTemp ) { printf( "ODNodeCreateRecord (create duplicate) - FAIL record returned\n" ); } else { CFIndex errCode = CFErrorGetCode( cfError ); if( errCode == kODErrorRecordAlreadyExists ) { printf( "ODNodeCreateRecord (create duplicate) - PASS\n" ); } else { printf( "ODNodeCreateRecord (create duplicate) - FAIL (%d)\n", (int) errCode ); CFRelease( cfError ); } } if( ODRecordDelete(cfRecord, &cfError) ) { printf( "ODRecordDelete - PASS\n" ); } else { printf( "ODRecordDelete - FAIL (%d)\n", (int) CFErrorGetCode(cfError) ); } CFRelease( cfRecord ); cfRecord = NULL; } else { printf( "ODNodeCreateRecord - FAIL\n" ); } CFMutableDictionaryRef cfAttributes = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); CFStringRef cfHome[] = { CFSTR("/Users/blah"), NULL }; CFStringRef cfNames[] = { cfAddRecordName, cfAddRecordAlias, NULL }; CFArrayRef cfHomeAttrib = CFArrayCreate( kCFAllocatorDefault, (const void **) &cfHome, 1, &kCFTypeArrayCallBacks ); CFArrayRef cfNamesAttrib = CFArrayCreate( kCFAllocatorDefault, (const void **) &cfNames, 2, &kCFTypeArrayCallBacks ); CFDictionarySetValue( cfAttributes, CFSTR(kDS1AttrNFSHomeDirectory), cfHomeAttrib ); CFDictionarySetValue( cfAttributes, CFSTR(kDSNAttrRecordName), cfNamesAttrib ); CFRelease( cfNamesAttrib ); CFRelease( cfHomeAttrib ); cfRecord = ODNodeCreateRecord( cfLocalNodeRef, CFSTR(kDSStdRecordTypeUsers), cfAddRecordName, cfAttributes, &cfError ); if( NULL != cfRecord ) { printf( "ODNodeCreateRecord (with attributes) - PASS\n" ); if( NULL != cfRecord ) { printf( "ODNodeAddRecordWithAttributes (record returned) - PASS\n" ); CFArrayRef cfValue = ODRecordCopyValues( cfRecord, CFSTR(kDS1AttrNFSHomeDirectory), NULL ); if( NULL != cfValue && CFArrayGetCount(cfValue) == 1 ) { printf( "ODNodeAddRecordWithAttributes (value exist) - PASS\n" ); } else { printf( "ODNodeAddRecordWithAttributes (value exist) - FAIL\n" ); } if( NULL != cfValue ) CFRelease( cfValue ); if( ODRecordChangePassword(cfRecord, NULL, CFSTR("test"), &cfError) ) { printf( "ODNodeSetPassword - PASS\n" ); } else { printf( "ODNodeSetPassword - FAIL (%d)\n", (int) CFErrorGetCode(cfError) ); CFRelease( cfError ); } if( ODRecordChangePassword(cfRecord, CFSTR("test"), CFSTR("test2"), &cfError) ) { printf( "ODNodeChangePassword - PASS\n" ); } else { printf( "ODNodeChangePassword - FAIL (%d)\n", (int) CFErrorGetCode(cfError) ); CFRelease( cfError ); } if( ODRecordSetValue( cfRecord, CFSTR(kDSNAttrState), CFSTR("Test street"), &cfError ) ) { printf( "ODRecordSetValueOrValues - PASS\n" ); } else { printf( "ODRecordSetValueOrValues - FAIL (%d)\n", (int) CFErrorGetCode(cfError) ); CFRelease( cfError ); } if( ODRecordAddValue( cfRecord, CFSTR(kDSNAttrState), CFSTR("Test street 2"), &cfError ) ) { printf( "ODRecordAddValue - PASS\n" ); } else { printf( "ODRecordAddValue - FAIL (%d)\n", (int) CFErrorGetCode(cfError) ); CFRelease( cfError ); } if( ODRecordRemoveValue(cfRecord, CFSTR(kDSNAttrState), CFSTR("Test street 2"), &cfError) ) { printf( "ODRecordRemoveValue - PASS\n" ); } else { printf( "ODRecordRemoveValue - FAIL (%d)\n", (int) CFErrorGetCode(cfError) ); } CFArrayRef cfArray = CFArrayCreate( kCFAllocatorDefault, NULL, 0, &kCFTypeArrayCallBacks ); if( ODRecordSetValue(cfRecord, CFSTR(kDSNAttrState), cfArray, &cfError) ) { printf( "ODRecordSetValue (remove attribute) - PASS\n" ); CFArrayRef cfValues = ODRecordCopyValues( cfRecord, CFSTR(kDSNAttrState), NULL ); if( NULL == cfValues || CFArrayGetCount(cfValues) == 0 ) { printf( "ODRecordSetValue (attrib gone) - PASS\n" ); } else { printf( "ODRecordSetValue (attrib gone) - FAIL\n" ); } if( NULL != cfValues ) CFRelease( cfValues ); } else { printf( "ODRecordSetValue (deleting attrib) - FAIL (%d)\n", (int) CFErrorGetCode(cfError) ); } CFRelease( cfArray ); ODRecordDelete( cfRecord, NULL ); } else { printf( "ODNodeAddRecordWithAttributes (record returned) - FAIL\n" ); } CFRelease( cfRecord ); cfRecord = NULL; } else { printf( "ODNodeCreateRecord (with attributes) - FAIL (%d)\n", (int) CFErrorGetCode(cfError) ); CFRelease( cfError ); } CFRelease( cfAttributes ); cfAttributes = NULL; // test various combinations ODRecordType groupTypes[] = { kODRecordTypeConfiguration, kODRecordTypeUsers, kODRecordTypeGroups, kODRecordTypeComputerGroups, kODRecordTypeComputerLists }; ODRecordType userTypes[] = { NULL, kODRecordTypeUsers, kODRecordTypeComputers, kODRecordTypeGroups, kODRecordTypeComputerGroups, kODRecordTypeComputerLists, kODRecordTypeConfiguration }; int groupX; int userX; bool bSuccess = true; for ( groupX = 0; bSuccess == true && groupX < (sizeof(groupTypes) / sizeof(ODRecordType)); groupX++ ) { for ( userX = 0; bSuccess == true && userX < (sizeof(userTypes) / sizeof(ODRecordType)); userX++ ) { bSuccess = doTestMembership( cfLocalNodeRef, groupTypes[groupX], userTypes[userX] ); } } if ( bSuccess == false ) return NULL; // now test membership checks ODRecordRef cfGroup = ODNodeCopyRecord( cfLocalNodeRef, kODRecordTypeGroups, CFSTR("admin"), NULL, NULL ); if( NULL != cfGroup ) { printf( "\n--Test Memberships\n" ); printf( "ODNodeCopyRecord (admin) - PASS\n" ); cfRecord = ODNodeCopyRecord( cfLocalNodeRef, kODRecordTypeUsers, cfAdminAccount, NULL, NULL ); if ( ODRecordContainsMember( cfGroup, cfRecord, NULL ) == true ) { printf( "ODRecordContainsMember - PASS\n" ); } else { printf( "ODRecordContainsMember - FAIL\n" ); } // test failure - group in user if ( ODRecordContainsMember(cfRecord, cfGroup, NULL) == false ) { printf( "ODRecordContainsMember (group is member of user (failure)) - PASS (got error)\n" ); } else { printf( "ODRecordContainsMember (group is member of user (failure)) - FAIL (no error)\n" ); } // test failure - group in group if ( ODRecordContainsMember(cfRecord, cfGroup, NULL) == false ) { printf( "ODRecordContainsMember (group is member of group (failure)) - PASS (got error)\n" ); } else { printf( "ODRecordContainsMember (group is member of group (failure)) - FAIL (no error)\n" ); } CFRelease( cfGroup ); cfGroup = NULL; } else { printf( "ODNodeCopyRecord (admin) - FAIL\n" ); } } else { printf( "ODNodeSetCredentials - FAIL\n" ); } CFRelease( cfLocalNodeRef ); cfLocalNodeRef = NULL; } else { printf( "ODNodeCreateWithNodeType with kODTypeLocalNode - FAIL (%d)\n", (int) CFErrorGetCode(cfError) ); CFRelease( cfError ); } } CFRelease( cfRecordName ); CFRelease( cfGroupName ); CFRelease( cfAddRecordName ); CFRelease( cfAddRecordAlias ); return NULL; } int main( int argc, char *argv[] ) { parseOptions( argc, argv ); argc -= optind; argv += optind; ODNodeRef cfLocalNodeRef = ODNodeCreateWithNodeType( kCFAllocatorDefault, kODSessionDefault, kODNodeTypeLocalNodes, NULL ); if ( gCopies > 0 ) { int ii; void *junk; pthread_t *threads = (pthread_t *) calloc( gCopies, sizeof(pthread_t) ); for ( ii = 0; ii < gCopies; ii++ ) { while( pthread_create( &threads[ii], NULL, doTest, cfLocalNodeRef ) != 0 ) { usleep( 1000 ); } } // now wait for each thread to finish for ( ii = 0; ii < gCopies; ii++ ) { pthread_join( threads[ii], &junk ); } } else { doTest( cfLocalNodeRef ); } return 0; }