static bool isLegacyGroup( ODRecordRef inRecordRef, CFArrayRef* outShortNameMembers ) { CFIndex shortNameMembersCount = 0; CFIndex guidMembersCount = 0; CFArrayRef shortNameMembers = ODRecordCopyValues( inRecordRef, kODAttributeTypeGroupMembership, NULL ); if ( shortNameMembers != NULL ) { shortNameMembersCount = CFArrayGetCount( shortNameMembers ); if ( outShortNameMembers != NULL ) { *outShortNameMembers = shortNameMembers; CFRetain( shortNameMembers ); } CFRelease( shortNameMembers ); } CFArrayRef guidMembers = ODRecordCopyValues( inRecordRef, kODAttributeTypeGroupMembers, NULL ); if ( guidMembers != NULL ) { guidMembersCount = CFArrayGetCount( guidMembers ); CFRelease( guidMembers ); } return ( guidMembersCount == 0 && shortNameMembersCount > 0 ); }
static uid_t uid_from_odrecord(ODRecordRef record) { uid_t uid = -2; CFArrayRef values = NULL; values = ODRecordCopyValues(record, CFSTR(kDS1AttrUniqueID), NULL); if ((values != NULL) && (CFArrayGetCount(values) > 0)) { char buf[64]; char * end; CFStringRef uidStr; unsigned long val; uidStr = CFArrayGetValueAtIndex(values, 0); (void) _SC_cfstring_to_cstring(uidStr, buf, sizeof(buf), kCFStringEncodingASCII); errno = 0; val = strtoul(buf, &end, 0); if ((buf[0] != '\0') && (*end == '\0') && (errno == 0)) { uid = (uid_t)val; } } my_CFRelease(&values); return (uid); }
// MARK: - // MARK: Open Directory CFTypeRef WBODRecordCopyFirstValue(ODRecordRef record, ODAttributeType attribute) { CFArrayRef values = ODRecordCopyValues(record, attribute, NULL); if (!values) return NULL; CFTypeRef result = NULL; if (CFArrayGetCount(values) > 0) result = CFRetain(CFArrayGetValueAtIndex(values, 0)); CFRelease(values); return result; }
int odkerb_get_fabricated_im_handle(ODRecordRef userRecord, CFStringRef allegedShortName, CFStringRef realm, char im_handle[], size_t im_handle_size) { int retval = -1; CFArrayRef cfShortNames = NULL; CFStringRef cfIMHandle = NULL; CFErrorRef cfError = NULL; CFStringRef shortName = allegedShortName; ODKERB_PARAM_ASSERT(allegedShortName != NULL); ODKERB_PARAM_ASSERT(realm != NULL); ODKERB_PARAM_ASSERT(im_handle != 0); ODKERB_PARAM_ASSERT(im_handle_size > 0); *im_handle = '\0'; if (userRecord != NULL) { /* attempt to get the primary short name from the user record */ cfShortNames = ODRecordCopyValues(userRecord, kODAttributeTypeRecordName, &cfError); if (cfShortNames == NULL || cfError != NULL) { ODKERB_LOG_CFERROR(LOG_DEBUG, "Unable to find the short names", cfError); /* ignore this error, use the passed in allegedShortName parameter */ } else if (CFArrayGetCount(cfShortNames) == 0) { ODKERB_LOG_CFSTRING(LOG_DEBUG, "Unable to find the short names", allegedShortName); /* ignore this error, use the passed in allegedShortName parameter */ } else { CFStringRef cfShortName = CFArrayGetValueAtIndex(cfShortNames, 0); assert(cfShortName != 0); shortName = cfShortName; } } cfIMHandle = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@@%@"), shortName, realm); if (cfIMHandle == NULL) { ODKERB_LOG_ERRNO(LOG_ERR, ENOMEM); goto failure; } if (CFStringGetCString(cfIMHandle, im_handle, im_handle_size-1, kCFStringEncodingUTF8) == FALSE) goto failure; retval = 0; failure: CF_SAFE_RELEASE(cfError); CF_SAFE_RELEASE(cfIMHandle); CF_SAFE_RELEASE(cfShortNames); return retval; }
/* Can return NULL */ int od_record_attribute_create_cfarray(ODRecordRef record, CFStringRef attrib, CFArrayRef *out) { int retval = PAM_SUCCESS; if (NULL == record || NULL == attrib || NULL == out) { openpam_log(PAM_LOG_DEBUG, "NULL argument passed"); retval = PAM_SERVICE_ERR; goto cleanup; } *out = ODRecordCopyValues(record, attrib, NULL); cleanup: if (PAM_SUCCESS != retval) { if (NULL != out) { CFRelease(out); } } return retval; }
/* ------------------------------------------------------------------ * get_attr_from_record () */ static CFStringRef get_attr_from_record ( ODRecordRef in_rec_ref, CFStringRef in_attr ) { CFErrorRef cf_err_ref = NULL; CFArrayRef cf_arry_values = ODRecordCopyValues( in_rec_ref, in_attr, &cf_err_ref ); if ( !cf_arry_values ) return( NULL ); if ( CFArrayGetCount( cf_arry_values ) > 1 ) { msg_error( "aod: multiple attribute values (%d) found in record user record: %s for attribute: %s", (int)CFArrayGetCount( cf_arry_values ), CFStringGetCStringPtr( ODRecordGetRecordName( in_rec_ref ), kCFStringEncodingUTF8 ), CFStringGetCStringPtr( in_attr, kCFStringEncodingUTF8 ) ); CFRelease( cf_arry_values ); return( NULL ); } CFStringRef cf_str_out = CFArrayGetValueAtIndex( cf_arry_values, 0 ); CFRetain( cf_str_out ); CFRelease( cf_arry_values ); return( cf_str_out ); } /* get_attr_from_record */
int main(int argc, char *argv[]) { int ch; char *operation = nil; bool bReadOption = false; bool bCreateOption = false; bool bDeleteOption = false; bool bEditOption = false; bool bInteractivePwd = false; bool bNoVerify = false; bool bVerbose = false; bool bCheckMemberOption = false; char *nodename = nil; char *username = nil; bool bDefaultUser = false; bool bCompList = false; char *password = nil; char *addrecordname = nil; char *delrecordname = nil; char *recordtype = nil; char *gid = nil; char *guid = nil; char *smbSID = nil; char *realname = nil; char *keyword = nil; char *comment = nil; char *timeToLive = nil; char *groupname = nil; char *member = nil; char *format = nil; //be either "l" for legacy or "n" for new group format const char *grouptype = NULL; int exitcode = 0; uuid_t uuid; ODNodeRef aDSNodeRef = NULL; ODNodeRef aDSSearchRef = NULL; bool bContinueAdd = false; char *groupRecordName = nil; __block ODRecordRef aGroupRecRef = NULL; __block ODRecordRef aGroupRecRef2 = NULL; CFErrorRef aErrorRef = NULL; char *errorTok = NULL; if (argc < 2) { usage(); exit(0); } if ( strcmp(argv[1], "-appleversion") == 0 ) dsToolAppleVersionExit( argv[0] ); while ((ch = getopt(argc, argv, "LT:o:pqvn:m:u:P:a:d:t:i:g:r:k:c:s:S:f:?h")) != -1) { switch (ch) { case 'o': operation = strdup(optarg); if (operation != nil) { if ( strcasecmp(operation, "read") == 0 ) { bReadOption = true; } else if ( strcasecmp(operation, "create") == 0 ) { bCreateOption = true; } else if ( strcasecmp(operation, "delete") == 0 ) { bDeleteOption = true; } else if ( strcasecmp(operation, "edit") == 0 ) { bEditOption = true; } else if ( strcasecmp(operation, "checkmember") == 0 ) { bCheckMemberOption = true; } } break; case 'p': bInteractivePwd = true; break; case 'q': bNoVerify = true; break; case 'v': bVerbose = true; break; case 'm': member = strdup(optarg); break; case 'n': nodename = strdup(optarg); break; case 'u': username = strdup(optarg); break; case 'P': password = strdup(optarg); break; case 'a': addrecordname = strdup(optarg); break; case 'd': delrecordname = strdup(optarg); break; case 't': recordtype = strdup(optarg); break; case 'T': grouptype = optarg; break; case 'L': bCompList = true; break; case 'i': strtol( optarg, &errorTok, 10 ); if ( errorTok == NULL || errorTok[0] == '\0' ) { gid = strdup(optarg); } else { printf( "GID contains non-numeric characters\n" ); return EX_USAGE; } break; case 'g': uuid_clear( uuid ); // don't allow malformed UUIDs nor an empty one if ( uuid_parse(optarg, uuid) == 0 && uuid_is_null(uuid) == false ) { guid = strdup(optarg); } else { printf( "GUID provided is not a valid UUID\n" ); return EX_USAGE; } break; case 'r': realname = strdup(optarg); break; case 'k': keyword = strdup(optarg); break; case 'c': comment = strdup(optarg); break; case 's': timeToLive = strdup(optarg); break; case 'S': smbSID = strdup(optarg); break; case 'f': format = strdup(optarg); break; case '?': case 'h': default: { usage(); return EX_USAGE; } } } argc -= optind; argv += optind; if (argc == 0) { printErrorOrMessage( NULL, "No group name provided", bVerbose ); return EX_USAGE; } groupname = strdup( argv[0] ); if (!bCreateOption && !bDeleteOption && !bEditOption && !bCheckMemberOption) { bReadOption = true; //default option } if (username == nil) { struct passwd* pw = NULL; pw = getpwuid(getuid()); if (pw != NULL && pw->pw_name != NULL && pw->pw_name[0] != '\0') { username = strdup(pw->pw_name); } else { printf("***Username <-u username> must be explicitly provided in this shell***\n"); usage(); exit(0); } bDefaultUser = true; } if (bVerbose) { printf("dseditgroup verbose mode\n"); printf("Options selected by user:\n"); if (bReadOption) printf("Read option selected\n"); if (bCreateOption) printf("Create option selected\n"); if (bDeleteOption) printf("Delete option selected\n"); if (bEditOption) printf("Edit option selected\n"); if (bCheckMemberOption) printf("Checking membership selected\n"); if (bInteractivePwd) printf("Interactive password option selected\n"); if (bNoVerify) printf("User verification is disabled\n"); if (nodename) printf("Nodename provided as <%s>\n", nodename); if (username && !bDefaultUser) printf("Username provided as <%s>\n", username); else printf("Username determined to be <%s>\n", username); if ( password && !bInteractivePwd ) printf("Password provided as <%s>\n", password); if (addrecordname) printf("Recordname to be added provided as <%s>\n", addrecordname); if (delrecordname) printf("Recordname to be deleted provided as <%s>\n", delrecordname); if (recordtype) printf("Recordtype provided as <%s>\n", recordtype); if (grouptype) printf("Grouptype provided as <%s>\n", grouptype); if (gid) printf("GID provided as <%s>\n", gid); if (guid) printf("GUID provided as <%s>\n", guid); if (smbSID) printf("SID provided as <%s>\n", smbSID); if (realname) printf("Realname provided as <%s>\n", realname); if (keyword) printf("Keyword provided as <%s>\n", keyword); if (comment) printf("Comment provided as <%s>\n", comment); if (timeToLive) printf("TimeToLive provided as <%s>\n", timeToLive); if (groupname) printf("Groupname provided as <%s>\n", groupname); if (bCompList) printf("Will maintain computer lists when applicable\n" ); printf("\n"); } ODRecordType (^mapRecTypeWithDefault)(const char *, ODRecordType) = ^(const char *inType, ODRecordType inDefault) { if ( inType != NULL ) { if ( strcasecmp(inType, "user") == 0) { return kODRecordTypeUsers; } else if ( strcasecmp(inType, "group") == 0) { return kODRecordTypeGroups; } else if ( strcasecmp(inType, "computer") == 0) { return kODRecordTypeComputers; } else if ( strcasecmp(inType, "computergroup") == 0 ) { return kODRecordTypeComputerGroups; } } return inDefault; }; if (bCheckMemberOption == false && bReadOption == false && (!bNoVerify && ( !bDefaultUser && ( (password == nil) || bInteractivePwd ) ) || (bDefaultUser && bInteractivePwd)) ) { password = read_passphrase("Please enter user password:"******"." we default to the local node by passing nil as the node name to getNodeRef aDSNodeRef = aLocalNodeRef; bIsLocalNode = true; } else { // otherwise we pass the provided nodename to getNodeRef CFStringRef cfNodeName = CFStringCreateWithCString( kCFAllocatorDefault, nodename, kCFStringEncodingUTF8 ); if ( cfNodeName != NULL ) { aDSNodeRef = ODNodeCreateWithName( kCFAllocatorDefault, kODSessionDefault, cfNodeName, &aErrorRef ); CFRelease( cfNodeName ); if (aDSNodeRef == NULL) { exitcode = printErrorOrMessage(NULL, "Error locating specified node.", bVerbose); break; } if ( CFEqual(ODNodeGetName(aDSNodeRef), ODNodeGetName(aLocalNodeRef)) == true ) { bIsLocalNode = true; } } else { exitcode = printErrorOrMessage( NULL, "Error parsing node name.", bVerbose ); break; } } if ( aDSNodeRef == NULL ) { exitcode = printErrorOrMessage( &aErrorRef, "getNodeRef failed to obtain a node reference", bVerbose ); break; } aDSSearchRef = ODNodeCreateWithNodeType( kCFAllocatorDefault, kODSessionDefault, kODNodeTypeAuthentication, &aErrorRef ); CFStringRef groupNameCF = CFStringCreateWithCString( kCFAllocatorDefault, groupname, kCFStringEncodingUTF8 ); if ( groupNameCF == NULL ) { exitcode = EX_SOFTWARE; printErrorOrMessage( NULL, "Unable to parse groupname", bVerbose ); break; } CFArrayRef attribs = CFArrayCreate( kCFAllocatorDefault, (CFTypeRef *) &kODAttributeTypeStandardOnly, 1, &kCFTypeArrayCallBacks ); if ( attribs == NULL ) { exitcode = EX_SOFTWARE; printErrorOrMessage( NULL, "Unable to allocate array", bVerbose ); break; } ODRecordType grpType = mapRecTypeWithDefault( grouptype, kODRecordTypeGroups ); bool (^isLocalNode)(ODRecordRef record) = ^(ODRecordRef record) { CFArrayRef values = ODRecordCopyValues( record, kODAttributeTypeMetaNodeLocation, NULL ); if ( values != NULL ) { if ( CFArrayGetCount(values) > 0 && CFEqual(CFArrayGetValueAtIndex(values, 0), ODNodeGetName(aLocalNodeRef)) == true ) { return (bool) true; } CFRelease( values ); } return (bool) false; }; aGroupRecRef = ODNodeCopyRecord( aDSNodeRef, grpType, groupNameCF, attribs, NULL ); if ( aGroupRecRef != NULL ) { bIsLocalNode = isLocalNode( aGroupRecRef ); } /* The group must already exist unless -o create is specified. */ if (aGroupRecRef == NULL && !bCreateOption) { exitcode = printErrorOrMessage(NULL, "Group not found.", bVerbose); break; } if ( bCompList == true && grpType == kODRecordTypeComputerGroups ) { aGroupRecRef2 = ODNodeCopyRecord( aDSNodeRef, kODRecordTypeComputerLists, groupNameCF, NULL, NULL ); if ( aGroupRecRef2 != NULL && isLocalNode(aGroupRecRef2) == true ) { // if we got a group record, let's see if it is also local node if ( bIsLocalNode == false && aGroupRecRef != NULL ) { if ( bVerbose == true ) { printf( "Skipping Computer list because it's on a different node\n" ); CFRelease( aGroupRecRef2 ); aGroupRecRef2 = NULL; } } else { bIsLocalNode = true; } } } if ( geteuid() == 0 && bIsLocalNode == true && (username == NULL || password == NULL) ) { // we are running as root and no password or name provided if ( bVerbose == true ) { printf( "Skipping authentication because user has effective ID 0\n" ); } } else if ( bDeleteOption == true || bCreateOption == true || bEditOption == true ) { // need to auth for changes if (username == NULL || password == NULL) { exitcode = printErrorOrMessage(NULL, "Username and password must be provided.", bVerbose); break; } bool bSuccess = false; CFStringRef user = CFStringCreateWithCString(NULL, username, kCFStringEncodingUTF8); CFStringRef pass = CFStringCreateWithCString(NULL, password, kCFStringEncodingUTF8); /* * aDSNodeRef may be /Search unless we're creating a new group. Fortunately, * we can authenticate with the specific group(s) most of the time. We still * authenticate with the node directly when the specified group doesn't exist. * As noted above, this is only allowed when creating a new group, in which * case aDSNodeRef cannot be /Search. */ if (aGroupRecRef != NULL) { bSuccess = ODRecordSetNodeCredentials(aGroupRecRef, user, pass, &aErrorRef); if (aGroupRecRef2 != NULL) { ODRecordSetNodeCredentials(aGroupRecRef2, user, pass, &aErrorRef); } } else { bSuccess = ODNodeSetCredentials(aDSNodeRef, NULL, user, pass, &aErrorRef); } CFRelease(user); CFRelease(pass); if (!bSuccess) { exitcode = printErrorOrMessage(&aErrorRef, "Failed to set credentials.", bVerbose); break; } } CFErrorRef (^deleteRecords)(void) = ^(void) { CFErrorRef error = NULL; if ( aGroupRecRef != NULL ) { if ( ODRecordDelete(aGroupRecRef, &error) == false ) { return error; } CFRelease( aGroupRecRef ); aGroupRecRef = NULL; } if ( aGroupRecRef2 != NULL ) { if ( ODRecordDelete(aGroupRecRef2, &error) == false ) { return error; } CFRelease( aGroupRecRef2 ); aGroupRecRef2 = NULL; } return error; }; if ( bReadOption == true || bDeleteOption == true ) { if ( aGroupRecRef != NULL || aGroupRecRef2 != NULL ) { if ( bDeleteOption == true && aGroupRecRef != NULL ) { printErrorOrMessage( NULL, "Group record below will be deleted:", bVerbose ); } CFDictionaryRef cfDetails = ODRecordCopyDetails( aGroupRecRef, NULL, NULL ); if ( cfDetails != NULL ) { CFDictionaryApplyFunction( cfDetails, printDictionary, NULL ); CFRelease( cfDetails ); } if ( bDeleteOption == true && (aErrorRef = deleteRecords()) != NULL ) { exitcode = printErrorOrMessage( &aErrorRef, "Unable to delete record", bVerbose ); break; } } else { exitcode = printErrorOrMessage( NULL, "Group was not found.", bVerbose ); break; } } else if (bCreateOption) { if ( aGroupRecRef != NULL || aGroupRecRef2 != NULL ) { char responseValue[8] = {0}; if (!bNoVerify) { printf("Create called on existing record - do you want to overwrite, y or n : "); scanf( "%c", responseValue ); printf("\n"); } if (bNoVerify || (responseValue[0] == 'y') || (responseValue[0] == 'Y')) { if ( (aErrorRef = deleteRecords()) != NULL ) { exitcode = printErrorOrMessage( &aErrorRef, "Unable to replace the record", bVerbose ); break; } } else { exitcode = EX_CANTCREAT; printErrorOrMessage( NULL, "Operation cancelled because record could not be replaced", bVerbose ); break; } } if ( aGroupRecRef == NULL ) { aGroupRecRef = ODNodeCreateRecord( aDSNodeRef, grpType, groupNameCF, NULL, &aErrorRef ); if ( aGroupRecRef != NULL ) { groupRecordName = strdup(groupname); bContinueAdd = true; // if creating ComputerGroups allow creation of ComputerLists if -L specified if ( bCompList == true && grpType == kODRecordTypeComputerGroups ) { aGroupRecRef2 = ODNodeCreateRecord( aDSNodeRef, kODRecordTypeComputerLists, groupNameCF, NULL, NULL ); } } else { exitcode = printErrorOrMessage( &aErrorRef, "Unable to create the record", bVerbose ); break; } } } else if (bEditOption) { if ( aGroupRecRef != NULL ) { bContinueAdd = true; } else { printErrorOrMessage( NULL, "Record not found", bVerbose ); break; } } else if (bCheckMemberOption) { if ( aGroupRecRef != NULL ) { const char *user = (member ? : username); CFStringRef memberCF = CFStringCreateWithCString( kCFAllocatorDefault, user, kCFStringEncodingUTF8 ); if ( memberCF == NULL ) { exitcode = printErrorOrMessage( &aErrorRef, "Unable to to allocate string", bVerbose ); break; } ODRecordRef memberRec = ODNodeCopyRecord( aDSSearchRef, kODRecordTypeUsers, memberCF, NULL, &aErrorRef ); if ( memberRec == NULL ) { exitcode = printErrorOrMessage( &aErrorRef, "Unable to find the user record", bVerbose ); break; } if ( ODRecordContainsMember(aGroupRecRef, memberRec, &aErrorRef) == true ) { // return default exitcode of 0 if they are a member printf("yes %s is a member of %s\n", user, groupname); exitcode = EX_OK; } else { printf("no %s is NOT a member of %s\n", user, groupname); exitcode = EX_NOUSER; } CFRelease( memberRec ); CFRelease( memberCF ); } else { exitcode = printErrorOrMessage( NULL, "Invalid group name", bVerbose ); break; } }
/* * Looks for kODAttributeTypeRecordName and * kODAttributeTypeAutomountInformation; if it finds them, it calls * the specified callback with that information. */ static callback_ret_t od_process_record_attributes(ODRecordRef record, callback_fn callback, void *udata) { CFErrorRef error; char *errstring; CFArrayRef keys; CFStringRef key; CFArrayRef values; CFStringRef value; callback_ret_t ret; if (trace > 1) { trace_prt(1, "od_process_record_attributes entered\n"); } /* * Get kODAttributeTypeRecordName and * kODAttributeTypeAutomountInformation for this record. * * Even though LDAP allows for multiple values per attribute, we take * only the 1st value for each attribute because the automount data is * organized as such (same as NIS+). */ error = NULL; keys = ODRecordCopyValues(record, kODAttributeTypeRecordName, &error); if (keys == NULL) { if (error != NULL) { errstring = od_get_error_string(error); pr_msg("od_process_record_attributes: can't get kODAttributeTypeRecordName attribute for record: %s", errstring); free(errstring); return (OD_CB_ERROR); } else { /* * We just reject records missing the attributes * we need. */ pr_msg("od_process_record_attributes: record has no kODAttributeTypeRecordName attribute"); return (OD_CB_REJECTED); } } if (CFArrayGetCount(keys) == 0) { /* * We just reject records missing the attributes * we need. */ CFRelease(keys); pr_msg("od_process_record_attributes: record has no kODAttributeTypeRecordName attribute"); return (OD_CB_REJECTED); } key = CFArrayGetValueAtIndex(keys, 0); error = NULL; values = ODRecordCopyValues(record, kODAttributeTypeAutomountInformation, &error); if (values == NULL) { CFRelease(keys); if (error != NULL) { errstring = od_get_error_string(error); pr_msg("od_process_record_attributes: can't get kODAttributeTypeAutomountInformation attribute for record: %s", errstring); free(errstring); return (OD_CB_ERROR); } else { /* * We just reject records missing the attributes * we need. */ pr_msg("od_process_record_attributes: record has no kODAttributeTypeAutomountInformation attribute"); return (OD_CB_REJECTED); } } if (CFArrayGetCount(values) == 0) { /* * We just reject records missing the attributes * we need. */ CFRelease(values); CFRelease(keys); pr_msg("od_process_record_attributes: record has no kODAttributeTypeRecordName attribute"); return (OD_CB_REJECTED); } value = CFArrayGetValueAtIndex(values, 0); /* * We have both of the attributes we need. */ ret = (*callback)(key, value, udata); CFRelease(values); CFRelease(keys); return (ret); }
/* * Looks for kODAttributeTypeRecordName and * kODAttributeTypeAutomountInformation; if it finds them, it prints them. */ static callback_ret_t od_print_record(ODRecordRef record) { CFErrorRef error; char *errstring; CFArrayRef keys; CFStringRef key; CFArrayRef values; CFStringRef value; char *key_cstring, *value_cstring; /* * Get kODAttributeTypeRecordName and * kODAttributeTypeAutomountInformation for this record. * * Even though LDAP allows for multiple values per attribute, we take * only the 1st value for each attribute because the automount data is * organized as such (same as NIS+). */ error = NULL; keys = ODRecordCopyValues(record, kODAttributeTypeRecordName, &error); if (keys == NULL) { if (error != NULL) { errstring = od_get_error_string(error); pr_msg("od_print_record: can't get kODAttributeTypeRecordName attribute for record: %s", errstring); free(errstring); return (OD_CB_ERROR); } else { /* * We just reject records missing the attributes * we need. */ pr_msg("od_print_record: record has no kODAttributeTypeRecordName attribute"); return (OD_CB_REJECTED); } } if (CFArrayGetCount(keys) == 0) { /* * We just reject records missing the attributes * we need. */ CFRelease(keys); pr_msg("od_print_record: record has no kODAttributeTypeRecordName attribute"); return (OD_CB_REJECTED); } key = CFArrayGetValueAtIndex(keys, 0); error = NULL; values = ODRecordCopyValues(record, kODAttributeTypeAutomountInformation, &error); if (values == NULL) { CFRelease(keys); if (error != NULL) { errstring = od_get_error_string(error); pr_msg("od_print_record: can't get kODAttributeTypeAutomountInformation attribute for record: %s", errstring); free(errstring); return (OD_CB_ERROR); } else { /* * We just reject records missing the attributes * we need. */ pr_msg("od_print_record: record has no kODAttributeTypeAutomountInformation attribute"); return (OD_CB_REJECTED); } } if (CFArrayGetCount(values) == 0) { /* * We just reject records missing the attributes * we need. */ CFRelease(values); CFRelease(keys); pr_msg("od_print_record: record has no kODAttributeTypeRecordName attribute"); return (OD_CB_REJECTED); } value = CFArrayGetValueAtIndex(values, 0); /* * We have both of the attributes we need. */ key_cstring = od_CFStringtoCString(key); value_cstring = od_CFStringtoCString(value); printf("%s %s\n", key_cstring, value_cstring); free(key_cstring); free(value_cstring); CFRelease(values); CFRelease(keys); return (OD_CB_KEEPGOING); }
int odkerb_get_im_handle_with_user_record(ODRecordRef userRecord, CFStringRef imType, CFStringRef realm, CFStringRef allegedShortName, char im_handle[], size_t im_handle_size) { int retval = -1; CFArrayRef cfIMHandles = NULL; CFErrorRef cfError = NULL; CFMutableArrayRef cfMatches = NULL; CFStringRef cfRealID = NULL; int i; ODKERB_PARAM_ASSERT(userRecord != NULL); ODKERB_PARAM_ASSERT(allegedShortName != NULL); ODKERB_PARAM_ASSERT(im_handle != 0); ODKERB_PARAM_ASSERT(im_handle_size > 0); *im_handle = '\0'; cfIMHandles = ODRecordCopyValues(userRecord, kODAttributeTypeIMHandle, &cfError); if (cfIMHandles == NULL || cfError != NULL) { ODKERB_LOG_CFERROR(LOG_ERR, "Unable to obtain IM handles", cfError); goto failure; } else if (CFArrayGetCount(cfIMHandles) == 0) { ODKERB_LOG_CFSTRING(LOG_DEBUG, "No IM handles", allegedShortName); goto failure; } /* there could be many IM handles that look plausible, so we heuristically determine which * one is the most likely to be the correct one. imagine, for instance, that the following * ones are available: * JABBER: [email protected] * JABBER: [email protected] * JABBER: [email protected] * YAHOO: [email protected] */ /* first, remove those of the wrong type or realm because they can't possibly be right */ cfMatches = CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, cfIMHandles); if (cfMatches == NULL) { ODKERB_LOG_ERRNO(LOG_ERR, ENOMEM); goto failure; } for (i = CFArrayGetCount(cfMatches) - 1; i >= 0; --i) { CFStringRef cfID = CFArrayGetValueAtIndex(cfMatches, i); if (cfID != NULL && odkerb_CFStringHasPrefixWithOptions(cfID, imType, kCFCompareCaseInsensitive) && odkerb_CFStringHasSuffixWithOptions(cfID, realm, kCFCompareCaseInsensitive)) continue; /* isn't a match, so remove it from the list */ CFArrayRemoveValueAtIndex(cfMatches, i); } CFStringRef match = NULL; if (CFArrayGetCount(cfMatches) == 0) { ODKERB_LOG_CFSTRING(LOG_INFO, "No IM handles matching type and realm", allegedShortName); goto failure; } else if (CFArrayGetCount(cfMatches) == 1) { match = CFArrayGetValueAtIndex(cfMatches, 0); goto found_match; } /* second, attempt to use the short name to disasmbiguate among the several choices */ for (i = 0; i < CFArrayGetCount(cfMatches); ++i) { CFStringRef cfID = CFArrayGetValueAtIndex(cfMatches, i); if (cfID == NULL) continue; CFRange where = CFStringFind(cfID, allegedShortName, kCFCompareCaseInsensitive | kCFCompareDiacriticInsensitive); if (where.location != kCFNotFound) { match = cfID; goto found_match; } } /* at this point, there are several possibilities, but none of them contain the * short name, so just choose the first one */ match = CFArrayGetValueAtIndex(cfMatches, 0); found_match: assert(match != NULL); /* the ID is the substring following the IM type specifier prefix (kIMTypeJABBER) */ assert(CFStringGetLength(match) > CFStringGetLength(imType)); cfRealID = CFStringCreateWithSubstring(kCFAllocatorDefault, match, CFRangeMake(CFStringGetLength(imType), CFStringGetLength(match)-CFStringGetLength(imType))); if (cfRealID == NULL) { ODKERB_LOG_ERRNO(LOG_ERR, ENOMEM); goto failure; } if (CFStringGetCString(cfRealID, im_handle, im_handle_size-1, kCFStringEncodingUTF8) == FALSE) { ODKERB_LOG_CFSTRING(LOG_ERR, "Cannot obtain IM handle string", cfRealID); goto failure; } retval = 0; failure: CF_SAFE_RELEASE(cfError); CF_SAFE_RELEASE(cfRealID); CF_SAFE_RELEASE(cfMatches); CF_SAFE_RELEASE(cfIMHandles); return retval; }
int odkerb_copy_search_node_with_config_record_name(CFStringRef configRecordName, ODNodeRef *out) { static CFTypeRef cfVals[2]; static CFArrayRef cfReqAttrs = NULL; int retval = -1; ODRecordRef cfConfigRecord = NULL; CFArrayRef cfOriginalNodeNames = NULL; CFErrorRef cfError = NULL; ODKERB_PARAM_ASSERT(configRecordName != NULL); ODKERB_PARAM_ASSERT(out != 0); *out = NULL; if (odkerb_configure_search_node() != 0) goto failure; if (cfReqAttrs == NULL) { /* hint for should be fetched */ cfVals[0] = kODAttributeTypeOriginalNodeName; cfVals[1] = kODAttributeTypeIMHandle; cfReqAttrs = CFArrayCreate(NULL, cfVals, 1, &kCFTypeArrayCallBacks); } cfConfigRecord = ODNodeCopyRecord(gSearchNode, kODRecordTypeConfiguration, configRecordName, cfReqAttrs, &cfError); if (cfConfigRecord == NULL || cfError != NULL) { ODKERB_LOG_CFERROR(LOG_ERR, "Unable to find the configuration record", cfError); goto failure; } cfOriginalNodeNames = ODRecordCopyValues(cfConfigRecord, kODAttributeTypeOriginalNodeName, &cfError); if (cfOriginalNodeNames == NULL || cfError != NULL) { ODKERB_LOG_CFERROR(LOG_ERR, "Unable to find the original node name", cfError); goto failure; } else if (CFArrayGetCount(cfOriginalNodeNames) == 0) { ODKERB_LOG_CFSTRING(LOG_ERR, "Unable to find the original node name", configRecordName); goto failure; } else if (CFArrayGetCount(cfOriginalNodeNames) > 1) { ODKERB_LOG_CFSTRING(LOG_DEBUG, "Too many original node names, using the first", configRecordName); } CFStringRef cfNodeName = CFArrayGetValueAtIndex(cfOriginalNodeNames, 0); if (cfNodeName == NULL) { ODKERB_LOG(LOG_ERR, "Missing original node name"); goto failure; } ODNodeRef cfSearchNode2 = ODNodeCreateWithName(kCFAllocatorDefault, kODSessionDefault, cfNodeName, &cfError); if (cfSearchNode2 == NULL || cfError != NULL) { ODKERB_LOG_CFERROR(LOG_ERR, "Unable to create the search record", cfError); goto failure; } *out = cfSearchNode2; retval = 0; failure: if (cfError != NULL) odkerb_possibly_reset_search_node(cfError); CF_SAFE_RELEASE(cfError); CF_SAFE_RELEASE(cfOriginalNodeNames); CF_SAFE_RELEASE(cfConfigRecord); return retval; }