/* * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /*! * @header DSAgent * DirectoryService agent for lookupd. */ #include #include #include #include #include #include #include #include #include #define DefaultTimeToLive 300 /* * This table MUST be kept up to date with the NetInfo plug-in * in Directory Services (number is 75 in CNiPlugIn.cpp) */ #define kAttrConsts 71 static const char *sAttrMap[kAttrConsts][2] = { { kDSNAttrRecordName, "name" }, { kDS1AttrDistinguishedName, "realname" }, { kDS1AttrPasswordPlus, "passwd" }, { kDS1AttrPassword, "passwd" }, /* needed when retrieving all so */ /* that standard type received gets */ /* correctly mapped */ { kDS1AttrUniqueID, "uid" }, { kDS1AttrPrimaryGroupID, "gid" }, { kDS1AttrUserShell, "shell" }, { kDS1AttrNFSHomeDirectory, "home" }, { kDSNAttrAuthenticationAuthority, "authentication_authority" }, { kDSNAttrHomeDirectory, "home_loc" }, { kDS1StandardAttrHomeLocOwner, "home_loc_owner" }, { kDS1AttrHomeDirectoryQuota, "homedirectoryquota" }, { kDS1AttrPicture, "picture" }, { kDS1AttrInternetAlias, "InetAlias" }, { kDS1AttrMailAttribute, "applemail" }, { kDS1AttrAuthenticationHint, "hint" }, { kDS1AttrRARA, "RARA" }, { kDS1AttrGeneratedUID, "GeneratedUID" }, { kDSNAttrGroupMembership, "users" }, { kDSNAttrEMailAddress, "mail" }, { kDSNAttrURL, "URL" }, { kDSNAttrURLForNSL, "URL" }, { kDSNAttrMIME, "mime" }, { kDSNAttrHTML, "htmldata" }, { kDSNAttrNBPEntry, "NBPEntry" }, { kDSNAttrDNSName, "dnsname" }, { kDSNAttrIPAddress, "IP_Address" }, { kDS1AttrENetAddress, "en_address" }, { kDSNAttrComputers, "computers" }, { kDS1AttrMCXFlags, "mcx_flags" }, { kDS1AttrMCXSettings, "mcx_settings" }, { kDS1AttrPrintServiceInfoText, "PrintServiceInfoText" }, { kDS1AttrPrintServiceInfoXML, "PrintServiceInfoXML" }, { kDS1AttrPrintServiceUserData, "appleprintservice" }, { kDS1AttrVFSType, "vfstype" }, { kDS1AttrVFSPassNo, "passno" }, { kDS1AttrVFSDumpFreq, "dump_freq" }, { kDS1AttrVFSLinkDir, "dir" }, { kDSNAttrVFSOpts, "opts" }, { kDS1AttrAliasData, "alias_data" }, { kDSNAttrPhoneNumber, "phonenumber" }, { kDS1AttrCapabilities, "capabilities" }, { kDSNAttrProtocols, "protocols" }, { kDSNAttrMember, "users" }, { kDS1AttrComment, "comment" }, { kDS1AttrAdminStatus, "AdminStatus" }, { kDS1AttrAdminLimits, "admin_limits" }, { kDS1AttrPwdAgingPolicy, "PwdAgingPolicy" }, { kDS1AttrChange, "change" }, { kDS1AttrExpire, "expire" }, { kDSNAttrGroup, "groups" }, { kDS1AttrFirstName, "firstname" }, { kDS1AttrMiddleName, "middlename" }, { kDS1AttrLastName, "lastname" }, { kDSNAttrAreaCode , "areacode" }, { kDSNAttrAddressLine1, "address1" }, { kDSNAttrAddressLine2, "address2" }, { kDSNAttrAddressLine3, "address3" }, { kDSNAttrCity, "city" }, { kDSNAttrState, "state" }, { kDSNAttrPostalCode, "zip" }, { kDSNAttrOrganizationName, "orgname" }, { kDS1AttrSetupOccupation, "occupation" }, { kDS1AttrSetupLocation, "location" }, { kDS1AttrSetupAdvertising, "spam" }, { kDS1AttrSetupAutoRegister, "autoregister" }, { kDS1AttrPresetUserIsAdmin, "preset_user_is_admin" }, { kDS1AttrPasswordServerLocation, "passwordserverlocation" }, { kDSNAttrBootParams, "bootparams" }, { kDSNAttrNetGroups, "netgroups" }, { kDSNAttrRecordAlias, "RecordAlias" } }; /* Static globals */ tDirReference gDirRef = 0; tDirNodeReference gNodeRef = 0; int gDSRunState = 0; int gCheckDSStarted = 0; syslock *gDSInitLock = NULL; static void __attribute__((constructor)) createInitLock(void) { gDSInitLock = syslock_new(0); } /* Static consts */ static const unsigned long kBuffSize = 2048; //starting size for the data buffer which can grow to accomodate returns typedef struct { time_t gSeconds; int gTimeToLive; dynainfo *dyna; } agent_private; static int doWeUseDS() { struct stat statResult; /* * ONLY if custom search policy is set then use DirectoryService */ if (stat("/Library/Preferences/DirectoryService/.DSRunningSP3", &statResult) == 0) { return 1; } return 0; } static int canWeWork(agent_private *ap, int forceReCheck) { tDirStatus status = eDSNoErr; tDataList *pDataList = NULL; tDataBuffer *pDataBuff = NULL; tDirReference dirRef = 0; tDirNodeReference nodeRef = 0; unsigned long count = 0; time_t timenow = 0; SCDynamicStoreRef aSCDStore = NULL; CFPropertyListRef aList = NULL; syslock_lock(gDSInitLock); /* don't want lookupd to kick start DS ie. let another process start it up */ /* can we use instead the mach port lookup of the DS running port to be added later to DS */ if (gCheckDSStarted == 0) { /* use CFStringRef instead of CFSTR since we can be multi-threaded and use no mutex */ CFStringRef storeString = CFStringCreateWithCString( NULL, "DirectoryService", kCFStringEncodingUTF8 ); aSCDStore = SCDynamicStoreCreate(NULL, storeString, NULL, NULL); CFRelease(storeString); if (aSCDStore == NULL) return 0; CFStringRef storePIDString = CFStringCreateWithCString( NULL, "DirectoryService:PID", kCFStringEncodingUTF8 ); aList = SCDynamicStoreCopyValue( aSCDStore, storePIDString ); CFRelease(storePIDString); if (aList == NULL) { CFRelease(aSCDStore); syslock_unlock(gDSInitLock); return 0; } CFRelease(aList); CFRelease(aSCDStore); gCheckDSStarted = 1; } timenow = time(NULL); /* Is it time to check or continue with past state */ if ( (ap->gSeconds > timenow) && (forceReCheck == 0) ) { /* Continuing with current state */ /* If DS was not running then return */ if (!gDSRunState) { syslock_unlock(gDSInitLock); return 0; } /* Else DS is running so we continue below to see if we have proper references */ } else { /* Time to check */ /* Don't bother if DS isn't running or DS should NOT be re-started */ if (doWeUseDS() == 0) { gDSRunState = 0; /* Set the time to the future */ ap->gSeconds = timenow + 30; syslock_unlock(gDSInitLock); return 0; } /* Else DS is running so we continue below to get the proper references */ } gDSRunState = 1; /* Set the time to the future */ ap->gSeconds = timenow + 30; /* verify that we have a valid dir ref otherwise get a new one */ if ((gDirRef == 0) || (dsVerifyDirRefNum(gDirRef) != eDSNoErr)) { gDirRef = 0; gNodeRef = 0; /* Open DirectoryService */ status = dsOpenDirService(&dirRef); if (status != eDSNoErr) { system_log(LOG_DEBUG, "-- DS: %d: *** Error *** %s: %s() error = %d.", __LINE__ , "cww", "dsOpenDirService failed", status); gDSRunState = 0; syslock_unlock(gDSInitLock); return 0; } else { gDirRef = dirRef; } } /* verify that we have a valid search node ref otherwise we get a new one */ if (gNodeRef == 0) { /* Allocate the data buffer to be used here - 512 chars max for search node name */ pDataBuff = dsDataBufferAllocate(gDirRef, 512); if (pDataBuff == NULL) { dsCloseDirService(gDirRef); gDirRef = 0; gDSRunState = 0; syslock_unlock(gDSInitLock); return 0; } /* Get the search node */ status = dsFindDirNodes(gDirRef, pDataBuff, NULL, eDSSearchNodeName, &count, NULL); /* if error or expecting only one search node returned */ if ((status != eDSNoErr) || (count != 1)) { system_log(LOG_DEBUG, "-- DS: %d: *** Error *** %s: %s() error = %d.", __LINE__, "cww", "dsFindDirNodes can't get search node", status); dsDataBufferDeAllocate(gDirRef, pDataBuff); dsCloseDirService(gDirRef); gDirRef = 0; gDSRunState = 0; syslock_unlock(gDSInitLock); return 0; } /* Allocate the tDataList to retrieve the search node name */ pDataList = dsDataListAllocate(gDirRef); if (pDataList == NULL) { dsDataBufferDeAllocate(gDirRef, pDataBuff); dsCloseDirService(gDirRef); gDirRef = 0; gDSRunState = 0; syslock_unlock(gDSInitLock); return 0; } /* Now get the search node name so we can open it - index is one based */ status = dsGetDirNodeName(gDirRef, pDataBuff, 1, &pDataList); if (status != eDSNoErr) { dsDataBufferDeAllocate(gDirRef, pDataBuff); dsDataListDeallocate(gDirRef, pDataList); free(pDataList); dsCloseDirService(gDirRef); gDirRef = 0; gDSRunState = 0; syslock_unlock(gDSInitLock); return 0; } /* Open the search node */ status = dsOpenDirNode(gDirRef, pDataList, &nodeRef); dsDataListDeallocate(gDirRef, pDataList); free(pDataList); if (status == eDSNoErr) { system_log(LOG_DEBUG, "-- DS: %d: %s: %s.", __LINE__, "cww", "Search node opened"); gNodeRef = nodeRef; } else { dsDataBufferDeAllocate(gDirRef, pDataBuff); dsCloseDirService(gDirRef); gDirRef = 0; gDSRunState = 0; syslock_unlock(gDSInitLock); return 0; } /* Deallocate the temp buff */ dsDataBufferDeAllocate(gDirRef, pDataBuff); } /* * if DS is running then we use it since in the case of NetInfo default DS can resolve aliases and * lookupd will have consulted NetInfo directly already and not found anything if it makes it here */ system_log(LOG_DEBUG, "-- DS: %d: %s: ap= %lu, gDirRef= %lu, gNodeRef= %lu.", __LINE__, "canWeWork", (unsigned long)ap, gDirRef, gNodeRef); gDSRunState = 1; syslock_unlock(gDSInitLock); return 1; } static char * mapDSAttrToNetInfoType(const char *inAttrType) { int i = 0; char *outResult = NULL; unsigned long uiStdLen = strlen(kDSStdAttrTypePrefix); if (inAttrType == NULL) return NULL; if (strncmp(inAttrType, kDSStdAttrTypePrefix, uiStdLen) == 0) { for (i = 0; i < kAttrConsts; i++) { if (strcmp(inAttrType, sAttrMap[i][0]) == 0) { outResult = (char *)malloc(strlen(sAttrMap[i][1]) + 1); strcpy(outResult, sAttrMap[i][1]); break; } } } return outResult; } static char * mapNetInfoAttrToDSType(const char *inAttrType) { int i = 0; char *outResult = NULL; if (inAttrType == NULL) return NULL; for (i = 0; i < kAttrConsts; i++) { if (strcmp(inAttrType, sAttrMap[i][1]) == 0) { outResult = (char *)malloc(strlen(sAttrMap[i][0]) + 1); strcpy(outResult, sAttrMap[i][0]); break; } } return outResult; } static char * mapNetInfoRecToDSType(LUCategory inCategory) { system_log(LOG_DEBUG, "-- DS: %d: mapNetInfoRecToDSType: *** category: %d", __LINE__, inCategory); switch (inCategory) { case LUCategoryUser: return(kDSStdRecordTypeUsers); case LUCategoryGroup: return(kDSStdRecordTypeGroups); case LUCategoryHost: return NULL; case LUCategoryNetwork: return NULL; case LUCategoryService: return NULL; case LUCategoryProtocol: return NULL; case LUCategoryRpc: return NULL; case LUCategoryMount: return(kDSStdRecordTypeMounts); case LUCategoryPrinter: return NULL; case LUCategoryBootparam: return NULL; case LUCategoryBootp: return NULL; case LUCategoryAlias: return NULL; case LUCategoryNetDomain: return NULL; case LUCategoryEthernet: return NULL; case LUCategoryNetgroup: return NULL; case LUCategoryInitgroups: return NULL; case LUCategoryHostServices: return NULL; default: system_log(LOG_DEBUG, "-- DS: %d: %s: *** Warning *** Unmapped category: %d", __LINE__, "mapNetInfoRecToDSType", inCategory); return NULL; } return NULL; } static dsrecord * dsrecordFromDS(agent_private *ap, tDataBuffer *buf, int which) { dsrecord *item; dsdata *d; dsattribute *a; tDirStatus status; tAttributeListRef attrListRef; tRecordEntry *pRecEntry; tAttributeEntry *pAttrEntry; tAttributeValueListRef valueRef; tAttributeValueEntry *pValueEntry; char *pNIKey; int i, j; attrListRef = 0; pRecEntry = NULL; status = dsGetRecordEntry(gNodeRef, buf, which, &attrListRef, &pRecEntry); if (status != eDSNoErr) return NULL; item = dsrecord_new(); for (i = 1; i <= pRecEntry->fRecordAttributeCount; i++) { pAttrEntry = NULL; valueRef = 0; status = dsGetAttributeEntry(gNodeRef, buf, attrListRef, i, &valueRef, &pAttrEntry); if (status != eDSNoErr) continue; pNIKey = mapDSAttrToNetInfoType(pAttrEntry->fAttributeSignature.fBufferData); if (pNIKey == NULL) { dsCloseAttributeValueList(valueRef); dsDeallocAttributeEntry(gDirRef, pAttrEntry); continue; } d = cstring_to_dsdata(pNIKey); a = dsattribute_new(d); dsdata_release(d); free(pNIKey); dsrecord_append_attribute(item, a, SELECT_ATTRIBUTE); for (j = 1; j <= pAttrEntry->fAttributeValueCount; j++) { pValueEntry = NULL; status = dsGetAttributeValue(gNodeRef, buf, j, valueRef, &pValueEntry); if (status != eDSNoErr) continue; d = cstring_to_dsdata(pValueEntry->fAttributeValueData.fBufferData); dsattribute_append(a, d); dsDeallocAttributeValueEntry(gDirRef, pValueEntry); } dsattribute_release(a); dsCloseAttributeValueList(valueRef); dsDeallocAttributeEntry(gDirRef, pAttrEntry); } dsCloseAttributeList(attrListRef); dsDeallocRecordEntry(gDirRef, pRecEntry); return item; } static void add_validation(dsrecord *r, int ttl) { dsdata *d; dsattribute *a; time_t best_before; char str[32]; if (r == NULL) return; d = cstring_to_dsdata("_lookup_validation"); dsrecord_remove_key(r, d, SELECT_ATTRIBUTE); a = dsattribute_new(d); dsrecord_append_attribute(r, a, SELECT_ATTRIBUTE); dsdata_release(d); best_before = time(0) + ttl; sprintf(str, "%lu", best_before); d = cstring_to_dsdata(str); dsattribute_append(a, d); dsdata_release(d); dsattribute_release(a); } u_int32_t DS_query(void *c, dsrecord *pattern, dsrecord **list) { agent_private *ap; u_int32_t cat; dsattribute *a; dsdata *k; dsrecord *lastrec; dsrecord *item = NULL; int match; tDirStatus status; char *pDSRecType, *catname; int i, idx; unsigned long ulRecCount = 0; unsigned long ulValidationStamp = 0; tDataList *pRecName = NULL, *pRecType = NULL, *pAttrType = NULL; tContextData pContext = NULL; tDataBuffer *pDataBuffer; int searchOnName = 0; /* if 1 we use dsGetRecordList else we use dsDoAttributeValueSearch */ tDataNode *pAttrSearchType = NULL, *pAttrSearchValue = NULL; int forceDSReCheckForMountQueries = 0; if (c == NULL) return 1; if (pattern == NULL) return 1; if (list == NULL) return 1; ap = (agent_private *)c; *list = NULL; lastrec = NULL; k = cstring_to_dsdata(CATEGORY_KEY); a = dsrecord_attribute(pattern, k, SELECT_META_ATTRIBUTE); dsdata_release(k); if (a == NULL) return 1; if (a->count == 0) return 1; dsrecord_remove_attribute(pattern, a, SELECT_META_ATTRIBUTE); catname = dsdata_to_cstring(a->value[0]); if (catname == NULL) { dsattribute_release(a); return 1; } cat = atoi(catname); dsattribute_release(a); pDSRecType = mapNetInfoRecToDSType(cat); if (pDSRecType == NULL) return 1; //we make sure that if a mount query comes in that we always recheck immediately to see if DS adds value if (cat == LUCategoryMount) { forceDSReCheckForMountQueries = 1; } /* we actually need to check DS (in our possible return 1 series)last since other conditions will drop us out */ /* of the search (like we don't service certain record types) before we grab a DS FW mutex ie. in dsVerifyRefNum */ if (canWeWork(ap, forceDSReCheckForMountQueries) == 0) return 1; k = cstring_to_dsdata(STAMP_KEY); a = dsrecord_attribute(pattern, k, SELECT_META_ATTRIBUTE); dsdata_release(k); if (a != NULL) { dsrecord_remove_attribute(pattern, a, SELECT_META_ATTRIBUTE); ulValidationStamp = 1; } dsattribute_release(a); if (ulValidationStamp == 1) { *list = dsrecord_new(); add_validation(*list, ap->gTimeToLive); return 0; } k = cstring_to_dsdata(SINGLE_KEY); a = dsrecord_attribute(pattern, k, SELECT_META_ATTRIBUTE); dsdata_release(k); if (a != NULL) { dsrecord_remove_attribute(pattern, a, SELECT_META_ATTRIBUTE); dsattribute_release(a); /* only retrieve a single record for this search */ /* therefore preset the record count to 1 */ ulRecCount = 1; } if (pattern->count == 0) searchOnName = 1; /* check if the "name" is in the pattern for our search */ for (i = 0; i < pattern->count; i++) { a = pattern->attribute[i]; if (a != NULL) { if (a->key != NULL) { if (a->key->data != NULL) { system_log(LOG_DEBUG, "-- DS: %d: %s: ap= %lu search on attr type = %s.", __LINE__, "DS_query", (unsigned long)ap, a->key->data); if (strcmp(a->key->data,"name") == 0) { if (a->value != NULL) { searchOnName = 1; pRecName = dsDataListAllocate(gDirRef); /* for (idx = 0; idx < a->count; idx++) */ if (a->count > 0) { idx = 0; /* don't need all the values provided here since we do an exact match later */ /* then each of the values must be present - so we need search only on the first */ /* we keep the code here in case the logic of multiple values becomes OR not the current AND */ if (dsdata_to_cstring(a->value[idx]) != NULL) { dsAppendStringToListAlloc(gDirRef, pRecName, a->value[idx]->data); system_log(LOG_DEBUG, "-- DS: %d: %s: ap= %lu search on attr type value = %s.", __LINE__, "DS_query", (unsigned long)ap, a->value[idx]->data); } } } break; } } } } } if (searchOnName == 0) /* if not searching on name */ { /* grab first pattern for our search call to DS */ for (i = 0; i < pattern->count; i++) { a = pattern->attribute[i]; if (a != NULL) { if (a->key != NULL) { if (a->key->data != NULL) { if (a->value != NULL) { /* for (idx = 0; idx < a->count; idx++) */ if (a->count > 0) { idx = 0; /* can't use all the values provided here but do an exact match later */ /* then each of the values must be present - so we need search only on the first */ /* we keep the code here in case the logic of multiple values becomes OR not the current AND */ if (dsdata_to_cstring(a->value[idx]) != NULL) { system_log(LOG_DEBUG, "-- DS: %d: %s: ap= %lu search on attr type value = %s of type = %s.", __LINE__, "DS_query", (unsigned long)ap, a->value[idx]->data, a->key->data); pAttrSearchValue = dsDataNodeAllocateString(gDirRef, a->value[idx]->data); if (pAttrSearchValue == NULL) { return 1; } } } /* grab the attr type as well - make sure it is a DS type*/ pAttrSearchType = dsDataNodeAllocateString(gDirRef, mapNetInfoAttrToDSType(a->key->data)); if (pAttrSearchType == NULL) { if (pAttrSearchValue == NULL) { dsDataNodeDeAllocate(gDirRef, pAttrSearchValue); } return 1; } break; } } } } } } /* check that we are looking for recName */ if (pRecName != NULL) { /* case where "name" was found in pattern but can't extract string out of value */ if (dsDataListGetNodeCount(pRecName) == 0) { pRecName = dsBuildListFromStrings(gDirRef, kDSRecordsAll, NULL); } } else if (searchOnName == 1) { /* case where no "name" pattern was provided for match */ if (pattern->count == 0) { pRecName = dsBuildListFromStrings(gDirRef, kDSRecordsAll, NULL); } else { /* this means we have already built the args for dsDoAttrValueSearch instead of dsGetRecordList */ } } /* And all attributes since this is required by the cache agent for subsequent calls */ //let's only retrieve what is really needed for the libInfo calls if (strcmp(pDSRecType, kDSStdRecordTypeUsers) == 0) { //native netinfo type "class" is not mapped pAttrType = dsBuildListFromStrings(gDirRef, kDSNAttrRecordName, kDS1AttrPassword, kDS1AttrPasswordPlus, kDS1AttrDistinguishedName, kDS1AttrNFSHomeDirectory, kDS1AttrUserShell, kDS1AttrUniqueID, kDS1AttrPrimaryGroupID, kDS1AttrChange, kDS1AttrExpire, NULL); } else if (strcmp(pDSRecType, kDSStdRecordTypeGroups) == 0) { pAttrType = dsBuildListFromStrings(gDirRef, kDSNAttrRecordName, kDS1AttrPassword, kDS1AttrPrimaryGroupID, kDSNAttrGroupMembership, NULL); } else if (strcmp(pDSRecType, kDSStdRecordTypeMounts) == 0) { //native netinfo type "type" is not mapped pAttrType = dsBuildListFromStrings(gDirRef, kDSNAttrRecordName, kDS1AttrVFSLinkDir, kDS1AttrVFSType, kDSNAttrVFSOpts, kDS1AttrVFSDumpFreq, kDS1AttrVFSPassNo, NULL); } else { pAttrType = dsBuildListFromStrings(gDirRef, kDSAttributesStandardAll, NULL); } if (pAttrType == NULL) { dsDataListDeallocate(gDirRef, pRecName); free(pRecName); return 1; } /* Of this record type */ pRecType = dsBuildListFromStrings(gDirRef, pDSRecType, NULL); if (pDSRecType != NULL) { /* DON'T free this since it is a constant returned from mapNetInfoRecToDSType */ pDSRecType = NULL; } if (pRecType == NULL) { dsDataListDeallocate(gDirRef, pAttrType); free(pAttrType); dsDataListDeallocate(gDirRef, pRecName); free(pRecName); return 1; } pDataBuffer = dsDataBufferAllocate(gDirRef, kBuffSize); if (pDataBuffer == NULL) { dsDataListDeallocate(gDirRef, pAttrType); free(pAttrType); dsDataListDeallocate(gDirRef, pRecName); free(pRecName); dsDataListDeallocate(gDirRef, pRecType); free(pRecType); return 1; } do { do { if (searchOnName == 1) { system_log(LOG_DEBUG, "-- DS: %d: %s: ap= %lu dsGetRecordList.", __LINE__, "DS_query", (unsigned long)ap); status = dsGetRecordList(gNodeRef, pDataBuffer, pRecName, eDSExact, pRecType, pAttrType, 0, &ulRecCount, &pContext); } else { system_log(LOG_DEBUG, "-- DS: %d: %s: ap= %lu dsDoAttributeValueSearchWithData.", __LINE__, "DS_query", (unsigned long)ap); status = dsDoAttributeValueSearchWithData(gNodeRef, pDataBuffer, pRecType, pAttrSearchType, eDSExact, pAttrSearchValue, pAttrType, 0, &ulRecCount, &pContext); } if (status == eDSBufferTooSmall) { unsigned long bufSize = pDataBuffer->fBufferSize; dsDataBufferDeAllocate(gDirRef, pDataBuffer); pDataBuffer = NULL; pDataBuffer = dsDataBufferAllocate(gDirRef, bufSize * 2); } } while (status == eDSBufferTooSmall); /* If the node ref is invalid then reset it to zero */ if (status == eDSInvalidNodeRef) gNodeRef = 0; /* Check for error and at least one record found. */ if ((status == eDSNoErr) && (ulRecCount != 0)) { for (i = 1; i <= ulRecCount; i++) { item = dsrecordFromDS(ap, pDataBuffer, i); if (item != NULL) { match = dsrecord_match(item, pattern); if (match == 1) { add_validation(item, ap->gTimeToLive); if (*list == NULL) *list = dsrecord_retain(item); else lastrec->next = dsrecord_retain(item); lastrec = item; } dsrecord_release(item); } } } } while ((status == eDSNoErr) && (pContext != NULL)); if (pRecType != NULL) { dsDataListDeallocate(gDirRef, pRecType); free(pRecType); } if (pAttrType != NULL) { dsDataListDeallocate(gDirRef, pAttrType); free(pAttrType); } if (pRecName != NULL) { dsDataListDeallocate(gDirRef, pRecName); free(pRecName); } if (pDataBuffer != NULL) { dsDataBufferDeAllocate(gDirRef, pDataBuffer); pDataBuffer = NULL; } if (pAttrSearchType != NULL) { dsDataNodeDeAllocate(gDirRef, pAttrSearchType); pAttrSearchType = NULL; } if (pAttrSearchValue != NULL) { dsDataNodeDeAllocate(gDirRef, pAttrSearchValue); pAttrSearchValue = NULL; } return 0; } u_int32_t DS_new(void **c, char *args, dynainfo *d) { agent_private *ap; dsrecord *r; dsattribute *a; dsdata *x; int status; if (c == NULL) return 1; ap = (agent_private *)malloc(sizeof(agent_private)); *c = ap; /* Can DS do the work or are we a noop */ //gDSRunState = 0; /* How long before we check our run state */ ap->gSeconds = 0; /* Have we verified that DS is already running */ //ap->gCheckDSStarted = 0; /* DS reference and search node reference are globals since DS FW is single threaded */ //gDirRef = 0; //gNodeRef = 0; ap->dyna = d; system_log(LOG_DEBUG, "Allocated DS 0x%08x\n", (int)ap); ap->gTimeToLive = DefaultTimeToLive; r = NULL; if (ap->dyna != NULL) { if (ap->dyna->dyna_config_agent != NULL) { status = (ap->dyna->dyna_config_agent)(ap->dyna, -1, &r); if (status == 0) { x = cstring_to_dsdata("TimeToLive"); a = dsrecord_attribute(r, x, SELECT_ATTRIBUTE); dsdata_release(x); if (a != NULL) { x = dsattribute_value(a, 0); if (x != NULL) { ap->gTimeToLive = atoi(dsdata_to_cstring(x)); dsdata_release(x); } dsattribute_release(a); } dsrecord_release(r); } } } return 0; } u_int32_t DS_free(void *c) { agent_private *ap; if (c == NULL) return 0; ap = (agent_private *)c; system_log(LOG_DEBUG, "Deallocated DS 0x%08x\n", (int)ap); //dsCloseDirNode(gNodeRef); //dsCloseDirService(gDirRef); free(ap); c = NULL; return 0; } u_int32_t DS_validate(void *c, char *v) { u_int32_t t; if (v == NULL) return 0; t = atoi(v); if (time(0) > t) return 0; return 1; }