X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_manifest/lib/ManifestInternal.cpp?ds=sidebyside diff --git a/Security/libsecurity_manifest/lib/ManifestInternal.cpp b/Security/libsecurity_manifest/lib/ManifestInternal.cpp new file mode 100644 index 00000000..2c8abdcc --- /dev/null +++ b/Security/libsecurity_manifest/lib/ManifestInternal.cpp @@ -0,0 +1,1161 @@ +/* + * Copyright (c) 2004-2006,2011-2014 Apple 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@ + */ + + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Manifest.h" + +ModuleNexus CSSMInitializer::mInstance; + +CSSMInitializer::CSSMInitializer () : mModule (gGuidAppleCSP), mCSP (mModule) +{ +} + + + +CSSMInitializer::~CSSMInitializer () +{ +} + + + +CssmClient::CSP* CSSMInitializer::GetCSP () +{ + return &mInstance().mCSP; +} + + + +//========================== MANIFEST ITEM LIST ========================== + + + +ManifestItemList::ManifestItemList () +{ +} + + + +ManifestItemList::~ManifestItemList () +{ + // throw away all of the items in the list + iterator it = begin (); + while (it != end ()) + { + delete *it++; + } +} + + + +// return the path portion of a URL after checking to see if we support its scheme +void ManifestItemList::DecodeURL (CFURLRef url, char *pathBuffer, CFIndex maxBufLen) +{ + // get the scheme from the url and check to make sure it is a "file" scheme + CFRef scheme (CFURLCopyScheme (url)); + if (CFStringCompare (scheme, CFSTR("file"), 0) != 0) + { + // we only support file URL's + MacOSError::throwMe (errSecManifestNotSupported); + } + + // convert the url into a "real" path name + if (!CFURLGetFileSystemRepresentation (url, false, (UInt8*) pathBuffer, maxBufLen)) + { + MacOSError::throwMe (errSecManifestNotEqual); + } +} + + + +void ManifestItemList::AddFileSystemObject (char* path, StringSet& exceptions, bool isRoot, bool hasAppleDoubleResourceFork) +{ + // see if our path is in the exception list. If it is, do nothing else + StringSet::iterator it = exceptions.find (path); + if (it != exceptions.end ()) + { + secdebug ("manifest", "Did not add %s to the manifest.", path); + return; + } + + // now that we have the path, do a stat and see what we have + struct stat nodeStat; + int result = lstat (path, &nodeStat); + UnixError::check (result); + + FileSystemEntryItem* mItem; + + bool includeUserAndGroup = true; + + switch (nodeStat.st_mode & S_IFMT) + { + case S_IFDIR: // are we a directory? + { + ManifestDirectoryItem* dirItem = new ManifestDirectoryItem (); + dirItem->SetPath (path, exceptions, isRoot); + mItem = dirItem; + } + break; + + case S_IFREG: + { + ManifestFileItem* fileItem = new ManifestFileItem (); + fileItem->SetPath (path); + fileItem->ComputeRepresentations (nodeStat, hasAppleDoubleResourceFork); + mItem = fileItem; + } + break; + + case S_IFLNK: + { + ManifestSymLinkItem* symItem = new ManifestSymLinkItem (); + symItem->SetPath (path); + symItem->ComputeRepresentation (); + mItem = symItem; + nodeStat.st_mode = S_IFLNK; + includeUserAndGroup = false; + } + break; + + default: + { + ManifestOtherItem* otherItem = new ManifestOtherItem (); + otherItem->SetPath (path); + mItem = otherItem; + } + break; + } + + if (includeUserAndGroup) // should we set the info? + { + mItem->SetUID (nodeStat.st_uid); + mItem->SetGID (nodeStat.st_gid); + } + + mItem->SetMode (nodeStat.st_mode); + + push_back (mItem); +} + + + +void ManifestItemList::AddDataObject (CFDataRef object) +{ + // reconstruct the pointer + SHA1Digest digest; + CC_SHA1_CTX digestContext; + + CC_SHA1_Init (&digestContext); + + const UInt8* data = CFDataGetBytePtr (object); + CFIndex length = CFDataGetLength (object); + + CC_SHA1_Update (&digestContext, data, (CC_LONG)length); + CC_SHA1_Final (digest, &digestContext); + + ManifestDataBlobItem* db = new ManifestDataBlobItem (); + + db->SetDigest (&digest); + db->SetLength (length); + + push_back (db); +} + + + +void ManifestItemList::ConvertToStringSet (const char* path, CFArrayRef exceptionList, StringSet &exceptions) +{ + if (exceptionList != NULL) + { + std::string prefix = path; + + // put us in canonical form + if (prefix[prefix.length () - 1] != '/') + { + prefix += '/'; + } + + // enumerate the list + CFIndex max = CFArrayGetCount (exceptionList); + CFIndex n; + + for (n = 0; n < max; ++n) + { + CFTypeRef dataRef = CFArrayGetValueAtIndex (exceptionList, n); + if (CFGetTypeID (dataRef) != CFStringGetTypeID ()) + { + MacOSError::throwMe (errSecManifestInvalidException); + } + + // always prepend the prefix -- the spec says that all items in the exception list are relative to the root + std::string s = prefix + cfString (CFStringRef (dataRef)); + secdebug ("manifest", "Uncanonicalized path is %s", s.c_str ()); + + // canonicalize the path and insert if successful. + char realPath [PATH_MAX]; + if (realpath (s.c_str (), realPath) != NULL) + { + secdebug ("manifest", "Inserted path %s as an exception", realPath); + exceptions.insert (realPath); + } + } + } +} + + + +void ManifestItemList::AddObject (CFTypeRef object, CFArrayRef exceptionList) +{ + // get the type of the object + CFTypeID objectID = CFGetTypeID (object); + + if (objectID == CFDataGetTypeID ()) + { + AddDataObject ((CFDataRef) object); + } + else if (objectID == CFURLGetTypeID ()) + { + StringSet exceptions; + + // get the path from the URL + char path [PATH_MAX]; + DecodeURL ((CFURLRef) object, path, sizeof (path)); + + // canonicalize + char realPath [PATH_MAX]; + if (realpath (path, realPath) == NULL) + { + UnixError::throwMe (); + } + + ConvertToStringSet (realPath, exceptionList, exceptions); + + AddFileSystemObject (realPath, exceptions, true, false); + } + else + { + MacOSError::throwMe (errSecManifestNotEqual); + } +} + + + +void RootItemList::Compare (RootItemList& item, bool compareOwnerAndGroup) +{ + // the number of items in the list has to be the same + unsigned numItems = (unsigned)size (); + + if (numItems != item.size ()) + { + MacOSError::throwMe (errSecManifestNotEqual); + } + + // for a root item list, items in the manifest MUST have the same creation order + unsigned i; + + for (i = 0; i < numItems; ++i) + { + ManifestItem* item1 = (*this)[i]; + ManifestItem* item2 = item[i]; + + if (item1->GetItemType () != item2->GetItemType ()) + { + MacOSError::throwMe (errSecManifestNotEqual); + } + + item1->Compare (item2, compareOwnerAndGroup); + } +} + + + +class CompareManifestFileItems +{ +public: + bool operator () (ManifestItem *a, ManifestItem *b); +}; + + + +bool CompareManifestFileItems::operator () (ManifestItem *a, ManifestItem *b) +{ + FileSystemEntryItem *aa = static_cast(a); + FileSystemEntryItem *bb = static_cast(b); + + return strcmp (aa->GetName (), bb->GetName ()) < 0; +} + + + +void FileSystemItemList::Compare (FileSystemItemList &a, bool compareOwnerAndGroup) +{ + unsigned numItems = (unsigned)size (); + + if (numItems != a.size ()) + { + MacOSError::throwMe (errSecManifestNotEqual); + } + + // sort the two lists + sort (begin (), end (), CompareManifestFileItems ()); + sort (a.begin (), a.end (), CompareManifestFileItems ()); + + // compare each item in the list + unsigned i; + for (i = 0; i < numItems; ++i) + { + ManifestItem *thisListPtr = (*this)[i]; + ManifestItem *aListPtr = a[i]; + if (thisListPtr->GetItemType () != aListPtr->GetItemType ()) + { + MacOSError::throwMe (errSecManifestNotEqual); + } + thisListPtr->Compare (aListPtr, compareOwnerAndGroup); + } +} + + + +//========================== MANIFEST ========================== + + + +ManifestInternal::ManifestInternal () +{ +} + + + +ManifestInternal::~ManifestInternal () +{ + secdebug ("manifest", "Destroyed manifest internal %p", this); +} + + + +void ManifestInternal::CompareManifests (ManifestInternal& m1, ManifestInternal& m2, SecManifestCompareOptions options) +{ + if ((options & ~kSecManifestVerifyOwnerAndGroup) != 0) + { + MacOSError::throwMe (errSecUnimplemented); // we don't support these options + } + + m1.mManifestItems.Compare (m2.mManifestItems, (bool) options & kSecManifestVerifyOwnerAndGroup); +} + + + +//========================== MANIFEST ITEM ========================== +ManifestItem::~ManifestItem () +{ +} + + + +//========================== DATA BLOB ITEM ========================== +ManifestDataBlobItem::ManifestDataBlobItem () +{ +} + + + +ManifestDataBlobItem::~ManifestDataBlobItem () +{ +} + + + +ManifestItemType ManifestDataBlobItem::GetItemType () +{ + return kManifestDataBlobItemType; +} + + + +const SHA1Digest* ManifestDataBlobItem::GetDigest () +{ + return &mSHA1Digest; +} + + + +void ManifestDataBlobItem::SetDigest (const SHA1Digest *sha1Digest) +{ + memcpy (&mSHA1Digest, sha1Digest, sizeof (SHA1Digest)); +} + + + +size_t ManifestDataBlobItem::GetLength () +{ + return mLength; +} + + + +void ManifestDataBlobItem::SetLength (size_t length) +{ + mLength = length; +} + + + +void ManifestDataBlobItem::Compare (ManifestItem* item, bool compareOwnerAndGroup) +{ + ManifestDataBlobItem* i = static_cast(item); + if (memcmp (&i->mSHA1Digest, &mSHA1Digest, sizeof (SHA1Digest)) != 0) + { + MacOSError::throwMe (errSecManifestNotEqual); + } +} + + + +//========================== FILE SYSTEM ENTRY ITEM ========================== + + + +FileSystemEntryItem::FileSystemEntryItem () : mUserID (0), mGroupID (0), mMode (0) +{ +} + + + +FileSystemEntryItem::~FileSystemEntryItem () +{ +} + + + +void FileSystemEntryItem::SetName (char* name) +{ + mName = name; +} + + + +static char* StringTail (char* path) +{ + char* finger = path + strlen (path) - 1; + while (finger != path && *finger != '/') + { + finger -= 1; + } + + if (finger != path) // did find a separator + { + finger += 1; + } + + return finger; +} + + + +void FileSystemEntryItem::SetPath (char* path) +{ + // save off the path + mPath = path; + + // while we are at it, extract that last name of the path name and save it off as the name + mName = StringTail (path); + secdebug ("manifest", "Created file item for %s with name %s", mPath.c_str (), mName.c_str ()); +} + + + +void FileSystemEntryItem::SetUID (uid_t uid) +{ + mUserID = uid; +} + + + +void FileSystemEntryItem::SetGID (gid_t gid) +{ + mGroupID = gid; +} + + + +void FileSystemEntryItem::SetMode (mode_t mode) +{ + mMode = mode; +} + + + +uid_t FileSystemEntryItem::GetUID () const +{ + return mUserID; +} + + +gid_t FileSystemEntryItem::GetGID () const +{ + return mGroupID; +} + + + +mode_t FileSystemEntryItem::GetMode () const +{ + return mMode; +} + + + +const char* FileSystemEntryItem::GetName () const +{ + return (char*) mName.c_str (); +} + + + +void FileSystemEntryItem::Compare (ManifestItem *aa, bool compareOwnerAndGroup) +{ + FileSystemEntryItem* a = static_cast(aa); + + if (mName != a->mName || mMode != a->mMode) + { + MacOSError::throwMe (errSecManifestNotEqual); + } + + if (compareOwnerAndGroup) + { + if (mUserID != a->mUserID || mGroupID != a->mGroupID) + { + MacOSError::throwMe (errSecManifestNotEqual); + } + } +} + + + +//========================== MANIFEST FILE ITEM ========================== + + + +bool ManifestFileItem::FileSystemHasTrueForks (char* pathToFile) +{ + // return true if volume to which path points supports true forked files + struct statfs st; + int result = statfs (pathToFile, &st); + if (result != 0) + { + secdebug ("manifest", "Could not get statfs (error was %s)", strerror (errno)); + UnixError::throwMe (); + } + + return strcmp (st.f_fstypename, "afpfs") == 0 || strcmp (st.f_fstypename, "hfs") == 0; +} + + + +std::string ManifestFileItem::ResourceFileName (char* path) +{ + std::string filePath; + + if (FileSystemHasTrueForks (path)) + { + filePath = path; + + return filePath + "/rsrc"; + } + else + { + return ""; + } + + return filePath; +} + + + +bool ManifestFileItem::HasResourceFork (char* pathToFile, std::string &result, struct stat &st) +{ + // try to get the stat on the file. If it works, the file exists + result = ResourceFileName (pathToFile); + if (result.length () != 0) + { + int stresult = lstat (result.c_str (), &st); + if (stresult == 0) + { + return st.st_size != 0; + } + } + + return false; +} + + + +ManifestFileItem::ManifestFileItem () : mNumForks (1) +{ +} + + + +ManifestFileItem::~ManifestFileItem () +{ + secdebug ("manifest", "Destroyed manifest item %p for path %s", this, mPath.c_str ()); +} + + + +ManifestItemType ManifestFileItem::GetItemType () +{ + return kManifestFileItemType; +} + + + +u_int32_t ManifestFileItem::GetNumberOfForks () +{ + return mNumForks; +} + + + +void ManifestFileItem::SetNumberOfForks (u_int32_t numForks) +{ + mNumForks = numForks; +} + + + +bool ManifestFileItem::FileIsMachOBinary (char* path) +{ + return false; +} + + + +void ManifestFileItem::SetForkLength (int which, size_t length) +{ + mFileLengths[which] = length; +} + + + +size_t ManifestFileItem::GetForkLength (int which) +{ + return mFileLengths[which]; +} + + + +void ManifestFileItem::ComputeRepresentations (struct stat &st, bool hasAppleDoubleResourceFork) +{ + // digest the data fork + mNumForks = 1; + ComputeDigestForFile ((char*) mPath.c_str (), mDigest[0], mFileLengths[0], st); + + struct stat stat2; + std::string resourceForkName; + if (hasAppleDoubleResourceFork) + { + mNumForks = 2; + + resourceForkName = mPath; + // walk back to find the beginning of the path and insert ._ + int i = (int)resourceForkName.length () - 1; + while (i >= 0 && resourceForkName[i] != '/') + { + i -= 1; + } + + i += 1; + + resourceForkName.insert (i, "._"); + + ComputeDigestForAppleDoubleResourceFork ((char*) resourceForkName.c_str(), mDigest[1], mFileLengths[1]); + } + else if (HasResourceFork ((char*) mPath.c_str (), resourceForkName, stat2)) + { + mNumForks = 2; + ComputeDigestForFile ((char*) resourceForkName.c_str (), mDigest[1], mFileLengths[1], stat2); + } +} + + + +static const int kReadChunkSize = 4096 * 4; + + + +static u_int32_t ExtractUInt32 (u_int8_t *&finger) +{ + u_int32_t result = 0; + int i; + for (i = 0; i < 4; ++i) + { + result = (result << 8) | *finger++; + } + + return result; +} + + + +void ManifestFileItem::ComputeDigestForAppleDoubleResourceFork (char* name, SHA1Digest &digest, size_t &fileLength) +{ + secdebug ("manifest", "Creating digest for AppleDouble resource fork %s", name); + + CC_SHA1_CTX digestContext; + CC_SHA1_Init (&digestContext); + + // bring the file into memory + int fileNo = open (name, O_RDONLY, 0); + if (fileNo == -1) + { + UnixError::throwMe (); + } + + // figure out how big the file is. + struct stat st; + int result = fstat (fileNo, &st); + if (result == -1) + { + UnixError::throwMe (); + } + + u_int8_t *buffer = new u_int8_t[st.st_size]; + ssize_t bytesRead = read (fileNo, buffer, (size_t)st.st_size); + close (fileNo); + + if (bytesRead != st.st_size) + { + delete buffer; + UnixError::throwMe (); + } + + // walk the entry table to find the offset to our resource fork + u_int8_t *bufPtr = buffer + 24; // size of the header + filler + + // compute the number of entries in the file + int numEntries = (((int) bufPtr[0]) << 8) | (int) (bufPtr [1]); + bufPtr += 2; + + ssize_t length = 0; + ssize_t offset = 0; + + int i; + for (i = 0; i < numEntries; ++i) + { + // bufPtr points to an entry descriptor. Four bytes for the ID, four for the offset, four for the length + ssize_t id = ExtractUInt32 (bufPtr); + offset = ExtractUInt32 (bufPtr); + length = ExtractUInt32 (bufPtr); + + if (id == 2) // is it the resource fork? + { + break; + } + } + + if (i >= numEntries) // did we run off the end? This had better not happen + { + MacOSError::throwMe (errSecManifestNotSupported); + } + + fileLength = length; + + // digest the data + CC_SHA1_Update (&digestContext, buffer + offset, (CC_LONG)length); + + // compute the SHA1 hash + CC_SHA1_Final (digest, &digestContext); + + delete buffer; +} + + + +void ManifestFileItem::ComputeDigestForFile (char* name, SHA1Digest &digest, size_t &fileLength, struct stat &st) +{ + secdebug ("manifest", "Creating digest for %s", name); + + // create a context for the digest operation + CC_SHA1_CTX digestContext; + CC_SHA1_Init (&digestContext); + + + int fileNo = open (name, O_RDONLY, 0); + if (fileNo == -1) + { + UnixError::throwMe (); + } + + fileLength = (size_t)st.st_size; + + if (st.st_size != 0) + { + // read the file + char buffer[kReadChunkSize]; + + ssize_t bytesRead; + while ((bytesRead = read (fileNo, buffer, kReadChunkSize)) != 0) + { + // digest the read data + CC_SHA1_Update (&digestContext, buffer, (CC_LONG)bytesRead); + } + + // compute the SHA1 hash + CC_SHA1_Final (digest, &digestContext); + } + + close (fileNo); +} + + + +void ManifestFileItem::GetItemRepresentation (int whichFork, void* &itemRep, size_t &size) +{ + itemRep = (void*) &mDigest[whichFork]; + size = kSHA1DigestSize; +} + + + +void ManifestFileItem::SetItemRepresentation (int whichFork, const void* itemRep, size_t size) +{ + memcpy ((void*) &mDigest[whichFork], itemRep, size); +} + + + +void ManifestFileItem::Compare (ManifestItem *manifestItem, bool compareOwnerAndGroup) +{ + FileSystemEntryItem::Compare (manifestItem, compareOwnerAndGroup); + + ManifestFileItem* item = static_cast< ManifestFileItem*>(manifestItem); + + secdebug ("manifest", "Comparing file item %s against %s", GetName (), item->GetName ()); + + // the number of forks should be equal + if (mNumForks != item->mNumForks) + { + MacOSError::throwMe (errSecManifestNotEqual); + } + + // compare file lengths + int i; + for (i = 0; i < mNumForks; ++i) + { + if (mFileLengths[i] != item->mFileLengths[i]) + { + MacOSError::throwMe (errSecManifestNotEqual); + } + + if (memcmp (&mDigest[i], item->mDigest[i], kSHA1DigestSize) != 0) + { + MacOSError::throwMe (errSecManifestNotEqual); + } + } +} + + + +//========================== MANIFEST DIRECTORY ITEM ========================== + + + +ManifestDirectoryItem::ManifestDirectoryItem () +{ +} + + + +ManifestDirectoryItem::~ManifestDirectoryItem () +{ + secdebug ("manifest", "Destroyed directory item %p for path %s", this, mPath.c_str ()); +} + + +const char* kAppleDoublePrefix = "._"; +const int kAppleDoublePrefixLength = 2; + +static int CompareFilenames (const FTSENT** a, const FTSENT** b) +{ + // ._name is always greater than name + // otherwise, ._ is ignored for sorting purposes + const char* aa = (*a)->fts_name; + const char* bb = (*b)->fts_name; + bool aHasPrefix = false; + + if (strncmp (aa, kAppleDoublePrefix, kAppleDoublePrefixLength) == 0) // do we have an appledouble prefix? + { + aHasPrefix = true; + aa += kAppleDoublePrefixLength; + } + + if (strncmp (bb, kAppleDoublePrefix, kAppleDoublePrefixLength) == 0) // do we have an appledouble prefix? + { + bb += kAppleDoublePrefixLength; + } + + int compare = strcmp (aa, bb); + + if (compare == 0 && aHasPrefix) + { + return 1; + } + + return compare; +} + + + +const u_int8_t kAppleDoubleMagicNumber[] = {0x00, 0x05, 0x16, 0x07}; + + + +static bool PathIsAppleDoubleFile (const char* path) +{ + // Open the file and check the "magic number". + int fRef = open (path, O_RDONLY, 0); + + u_int8_t buffer[4]; + + // read the first four bytes of the file + ssize_t bytesRead = read(fRef, buffer, 4); + if (bytesRead == -1) + { + int err = errno; + close (fRef); + UnixError::throwMe (err); + } + + close (fRef); + + if (bytesRead != 4) // did we get enough bytes? + { + return false; + } + + // what we got had better be the proper magic number for this file type + int i; + for (i = 0; i < 4; ++i) + { + if (buffer[i] != kAppleDoubleMagicNumber[i]) + { + return false; + } + } + + return true; +} + + + +void ManifestDirectoryItem::SetPath (char* path, StringSet &exceptions, bool isRoot) +{ + if (isRoot) + { + mName = "/"; + mPath = path; + } + else + { + FileSystemEntryItem::SetPath (path); + } + + secdebug ("manifest", "Added directory entry for %s with name %s", mPath.c_str (), mName.c_str ()); + + // enumerate the contents of the directory. + char* path_argv[] = { path, NULL }; + FTS* thisDir = fts_open (path_argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_NOSTAT | FTS_XDEV, CompareFilenames); + if (thisDir == NULL) // huh? The file disappeared or isn't a directory any more + { + UnixError::throwMe (); + } + + (void)fts_read(thisDir); + FTSENT* dirEnt = fts_children (thisDir, FTS_NAMEONLY); + + while (dirEnt != NULL) + { + // get the next entry + FTSENT* dirEntNext = dirEnt->fts_link; + bool hasAppleDoubleResourceFork = false; + + // see if it is an AppleDouble resource fork for this file + if (dirEntNext && + strncmp (dirEntNext->fts_name, kAppleDoublePrefix, kAppleDoublePrefixLength) == 0 && + strcmp (dirEnt->fts_name, dirEntNext->fts_name + kAppleDoublePrefixLength) == 0) + { + if (PathIsAppleDoubleFile ((mPath + "/" + dirEntNext->fts_name).c_str ())) + { + hasAppleDoubleResourceFork = true; + dirEntNext = dirEntNext->fts_link; + } + } + + // figure out what this is pointing to. + std::string fileName = mPath + "/" + dirEnt->fts_name; + + mDirectoryItems.AddFileSystemObject ((char*) fileName.c_str(), exceptions, false, hasAppleDoubleResourceFork); + + dirEnt = dirEntNext; + } + + fts_close(thisDir); +} + + + +ManifestItemType ManifestDirectoryItem::GetItemType () +{ + return kManifestDirectoryItemType; +} + + + +void ManifestDirectoryItem::Compare (ManifestItem* a, bool compareOwnerAndGroup) +{ + FileSystemEntryItem::Compare (a, compareOwnerAndGroup); + ManifestDirectoryItem* aa = static_cast(a); + secdebug ("manifest", "Comparing directory item %s against %s", GetName (), aa->GetName ()); + mDirectoryItems.Compare (aa->mDirectoryItems, compareOwnerAndGroup); +} + + + +//========================== MANIFEST SYMLINK ITEM ========================== + + + +ManifestSymLinkItem::ManifestSymLinkItem () +{ +} + + + +ManifestSymLinkItem::~ManifestSymLinkItem () +{ + secdebug ("manifest", "Destroyed symlink item for %s", mPath.c_str ()); +} + + + +void ManifestSymLinkItem::ComputeRepresentation () +{ + char path [FILENAME_MAX]; + int result = (int)readlink (mPath.c_str (), path, sizeof (path)); + secdebug ("manifest", "Read content %s for %s", path, mPath.c_str ()); + + // create a digest context + CC_SHA1_CTX digestContext; + CC_SHA1_Init (&digestContext); + + // digest the data + CC_SHA1_Update (&digestContext, path, result); + + // compute the result + CC_SHA1_Final (mDigest, &digestContext); + + UnixError::check (result); +} + + + +const SHA1Digest* ManifestSymLinkItem::GetDigest () +{ + return &mDigest; +} + + + +void ManifestSymLinkItem::SetDigest (const SHA1Digest* digest) +{ + memcpy (mDigest, digest, sizeof (SHA1Digest)); +} + + + +ManifestItemType ManifestSymLinkItem::GetItemType () +{ + return kManifestSymLinkItemType; +} + + + +void ManifestSymLinkItem::Compare (ManifestItem *a, bool compareOwnerAndGroup) +{ + FileSystemEntryItem::Compare (a, compareOwnerAndGroup); + ManifestSymLinkItem* aa = static_cast(a); + secdebug ("manifest", "Comparing symlink item %s against %s", GetName (), aa->GetName ()); + + // now compare the data + if (memcmp (&mDigest, &aa->mDigest, kSHA1DigestSize) != 0) + { + MacOSError::throwMe (errSecManifestNotEqual); + } +} + + + +//========================== MANIFEST OTHER ITEM ========================== + + + +ManifestOtherItem::ManifestOtherItem () +{ +} + + + +ManifestOtherItem::~ManifestOtherItem () +{ + secdebug ("manifest", "Destroyed other item for path %s", mPath.c_str ()); +} + + + +ManifestItemType ManifestOtherItem::GetItemType () +{ + return kManifestOtherType; +} + + + +void ManifestOtherItem::Compare (ManifestItem *a, bool compareOwnerAndGroup) +{ + FileSystemEntryItem::Compare (a, compareOwnerAndGroup); + secdebug ("manifest", "Comparing other item %s against %s", GetName (), static_cast(a)->GetName ()); +}