X-Git-Url: https://git.saurik.com/apple/securityd.git/blobdiff_plain/eeadf2e6470f45ea0275a6019635573f2a7b5a2c..ee396ef47db58c01c7ceaecfec60781c95ffeea1:/src/tokencache.cpp diff --git a/src/tokencache.cpp b/src/tokencache.cpp new file mode 100644 index 0000000..c843340 --- /dev/null +++ b/src/tokencache.cpp @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2004 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@ + */ + + +// +// tokencache - persistent (on-disk) hardware token directory +// +// Here's the basic disk layout, rooted at /var/db/TokenCache (or $TOKENCACHE): +// TBA +// +#include "tokencache.h" +#include +#include +#include + +using namespace UnixPlusPlus; + + +// +// Here are the uid/gid values we assign to token daemons and their cache files +// +#define TOKEND_UID "tokend" +#define TOKEND_GID "tokend" +#define TOKEND_UID_FALLBACK uid_t(-2) +#define TOKEND_GID_FALLBACK gid_t(-2) + + +// +// Fixed relative file paths +// + +// relative to cache root (use cache->path()) +static const char configDir[] = "config"; +static const char lastSSIDFile[] = "config/lastSSID"; +static const char tokensDir[] = "tokens"; + +// relative to token directory (use token->path()) +static const char ssidFile[] = "SSID"; +static const char workDir[] = "work"; +static const char cacheDir[] = "cache"; + + +// +// Internal file I/O helpers. These read/write entire files. +// Note that the defaulted read functions do NOT write the default +// to disk; they work fine in read-only disk areas. +// +static uint32 getFile(const string &path, uint32 defaultValue) +{ + try { + FileDesc fd(path); + string s; fd.readAll(s); + uint32 value; sscanf(s.c_str(), "%ld", &value); + return value; + } catch (...) { + return defaultValue; + } +} + +static string getFile(const string &path, const string &defaultValue) +{ + try { + FileDesc fd(path); + string s; fd.readAll(s); + return s; + } catch (...) { + return defaultValue; + } +} + + +static void putFile(const string &path, uint32 value) +{ + char buffer[64]; + snprintf(buffer, sizeof(buffer), "%ld\n", value); + FileDesc(path, O_WRONLY | O_CREAT | O_TRUNC).writeAll(buffer); +} + +static void putFile(const string &path, const string &value) +{ + FileDesc(path, O_WRONLY | O_CREAT | O_TRUNC).writeAll(value); +} + + +// +// The "rooted tree" utility class +// +void Rooted::root(const string &r) +{ + assert(mRoot.empty()); // can't re-set this + mRoot = r; +} + +string Rooted::path(const char *sub) const +{ + if (sub == NULL) + return mRoot; + return mRoot + "/" + sub; +} + + +// +// Open a TokenCache. +// If the cache does not exist at the path given, initialize it. +// If that fails, throw an exception. +// +TokenCache::TokenCache(const char *where) + : Rooted(where), mLastSubservice(0) +{ + makedir(root(), O_CREAT, 0711, securityd); + makedir(path(configDir), O_CREAT, 0700, securityd); + makedir(path(tokensDir), O_CREAT, 0711, securityd); + + // get the path for the SSID file. Don't call getFile unless the file exists (avoids exception overhead) + string idFilePath = path (lastSSIDFile); + struct stat st; + if (stat (idFilePath.c_str (), &st) == -1) { + mLastSubservice = 1; + } else { + mLastSubservice = getFile(idFilePath, 1); + } + + // identify uid/gid for token daemons + struct passwd *pw = getpwnam(TOKEND_UID); + mTokendUid = pw ? pw->pw_uid : TOKEND_UID_FALLBACK; + struct group *gr = getgrnam(TOKEND_GID); + mTokendGid = gr ? gr->gr_gid : TOKEND_GID_FALLBACK; + + secdebug("tokencache", "token cache rooted at %s (last ssid=%ld, uid/gid=%d/%d)", + root().c_str(), mLastSubservice, mTokendUid, mTokendGid); +} + +TokenCache::~TokenCache() +{ +} + + +// +// Get a new, unused subservice id number. +// Update the tracking file so we won't hand it out again (ever) within this cache. +// +uint32 TokenCache::allocateSubservice() +{ + putFile(path(lastSSIDFile), ++mLastSubservice); + return mLastSubservice; +} + + +// +// A slightly souped-up UnixPlusPlus::makedir +// +void TokenCache::makedir(const char *path, int flags, mode_t mode, Owner owner) +{ + UnixPlusPlus::makedir(path, flags, mode); + switch(owner) { + case securityd: + // leave it alone; we own it alrady + break; + case tokend: + ::chown(path, tokendUid(), tokendGid()); + break; + } +} + + +// +// Make a cache entry from a valid tokenUid. +// This will locate an existing entry or make a new one. +// +TokenCache::Token::Token(TokenCache &c, const string &tokenUid) + : Rooted(c.path(string(tokensDir) + "/" + tokenUid)), cache(c) +{ + cache.makedir(root(), O_CREAT, 0711, securityd); + if (mSubservice = getFile(path(ssidFile), 0)) { + secdebug("tokencache", "found token \"%s\" ssid=%ld", tokenUid.c_str(), mSubservice); + init(existing); + } else { + mSubservice = cache.allocateSubservice(); // allocate new, unique ssid... + putFile(path(ssidFile), mSubservice); // ... and save it in cache + secdebug("tokencache", "new token \"%s\" ssid=%ld", tokenUid.c_str(), mSubservice); + init(created); + } +} + + +// +// Make a cache entry that is temporary and will never be reused. +// +TokenCache::Token::Token(TokenCache &c) + : cache(c) +{ + mSubservice = cache.allocateSubservice(); // new, unique id + char rootForm[30]; snprintf(rootForm, sizeof(rootForm), + "%s/temporary:%ld", tokensDir, mSubservice); + root(cache.path(rootForm)); + cache.makedir(root(), O_CREAT | O_EXCL, 0711, securityd); + putFile(path(ssidFile), mSubservice); // ... and save it in cache + secdebug("tokencache", "temporary token \"%s\" ssid=%ld", rootForm, mSubservice); + init(temporary); +} + + +// +// Common constructor setup code +// +void TokenCache::Token::init(Type type) +{ + mType = type; + cache.makedir(workPath(), O_CREAT, 0700, tokend); + cache.makedir(cachePath(), O_CREAT, 0700, tokend); +} + + +// +// The Token destructor might clean or preen a bit, but shouldn't take +// too long (or too much effort). +// +TokenCache::Token::~Token() +{ + if (type() == temporary) + secdebug("tokencache", "@@@ should delete the cache directory here..."); +} + + +// +// Attributes of TokenCache::Tokens +// +string TokenCache::Token::workPath() const +{ + return path("Work"); +} + +string TokenCache::Token::cachePath() const +{ + return path("Cache"); +} + + +string TokenCache::Token::printName() const +{ + return getFile(path("PrintName"), ""); +} + +void TokenCache::Token::printName(const string &name) +{ + putFile(path("PrintName"), name); +}