]> git.saurik.com Git - apple/securityd.git/blobdiff - src/tokencache.cpp
securityd-61.tar.gz
[apple/securityd.git] / src / tokencache.cpp
diff --git a/src/tokencache.cpp b/src/tokencache.cpp
new file mode 100644 (file)
index 0000000..c843340
--- /dev/null
@@ -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 <security_utilities/unix++.h>
+#include <pwd.h>
+#include <grp.h>
+
+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);
+}