]> git.saurik.com Git - apple/security.git/blame - securityd/src/tokencache.cpp
Security-58286.200.222.tar.gz
[apple/security.git] / securityd / src / tokencache.cpp
CommitLineData
d8f41ccd
A
1/*
2 * Copyright (c) 2004-2006,2008 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25//
26// tokencache - persistent (on-disk) hardware token directory
27//
28// Here's the basic disk layout, rooted at /var/db/TokenCache (or $TOKENCACHE):
29// TBA
30//
31#include "tokencache.h"
32#include <security_utilities/unix++.h>
fa7225c8 33#include <security_utilities/casts.h>
d8f41ccd
A
34#include <pwd.h>
35#include <grp.h>
36
37using namespace UnixPlusPlus;
38
39
40//
41// Here are the uid/gid values we assign to token daemons and their cache files
42//
43#define TOKEND_UID "tokend"
44#define TOKEND_GID "tokend"
45#define TOKEND_UID_FALLBACK uid_t(-2)
46#define TOKEND_GID_FALLBACK gid_t(-2)
47
48
49//
50// Fixed relative file paths
51//
52
53// relative to cache root (use cache->path())
54static const char configDir[] = "config";
55static const char lastSSIDFile[] = "config/lastSSID";
56static const char tokensDir[] = "tokens";
57
58// relative to token directory (use token->path())
59static const char ssidFile[] = "SSID";
d8f41ccd
A
60
61
62//
63// Internal file I/O helpers. These read/write entire files.
64// Note that the defaulted read functions do NOT write the default
65// to disk; they work fine in read-only disk areas.
66//
67static unsigned long getFile(const string &path, unsigned long defaultValue)
68{
69 try {
70 AutoFileDesc fd(path, O_RDONLY, FileDesc::modeMissingOk);
71 if (fd) {
72 string s; fd.readAll(s);
73 unsigned long value; sscanf(s.c_str(), "%lu", &value);
74 return value;
75 }
76 } catch (...) {
77 }
78 return defaultValue;
79}
80
81static string getFile(const string &path, const string &defaultValue)
82{
83 try {
84 AutoFileDesc fd(path, O_RDONLY, FileDesc::modeMissingOk);
85 if (fd) {
86 string s; fd.readAll(s);
87 return s;
88 }
89 } catch (...) {
90 }
91 return defaultValue;
92}
93
94
95static void putFile(const string &path, uint32 value)
96{
97 char buffer[64];
fa7225c8 98 snprintf(buffer, sizeof(buffer), "%u\n", value);
d8f41ccd
A
99 AutoFileDesc(path, O_WRONLY | O_CREAT | O_TRUNC).writeAll(buffer);
100}
101
102static void putFile(const string &path, const string &value)
103{
104 AutoFileDesc(path, O_WRONLY | O_CREAT | O_TRUNC).writeAll(value);
105}
106
107
108//
109// The "rooted tree" utility class
110//
111void Rooted::root(const string &r)
112{
113 assert(mRoot.empty()); // can't re-set this
114 mRoot = r;
115}
116
117string Rooted::path(const char *sub) const
118{
119 if (sub == NULL)
120 return mRoot;
121 return mRoot + "/" + sub;
122}
123
124
125//
126// Open a TokenCache.
127// If the cache does not exist at the path given, initialize it.
128// If that fails, throw an exception.
129//
130TokenCache::TokenCache(const char *where)
131 : Rooted(where), mLastSubservice(0)
132{
133 makedir(root(), O_CREAT, 0711, securityd);
134 makedir(path(configDir), O_CREAT, 0700, securityd);
135 makedir(path(tokensDir), O_CREAT, 0711, securityd);
136
fa7225c8 137 mLastSubservice = int_cast<ssize_t, uint32>(getFile(path(lastSSIDFile), 1));
d8f41ccd
A
138
139 // identify uid/gid for token daemons
140 struct passwd *pw = getpwnam(TOKEND_UID);
141 mTokendUid = pw ? pw->pw_uid : TOKEND_UID_FALLBACK;
142 struct group *gr = getgrnam(TOKEND_GID);
143 mTokendGid = gr ? gr->gr_gid : TOKEND_GID_FALLBACK;
144
fa7225c8 145 secinfo("tokencache", "token cache rooted at %s (last ssid=%u, uid/gid=%d/%d)",
d8f41ccd
A
146 root().c_str(), mLastSubservice, mTokendUid, mTokendGid);
147}
148
149TokenCache::~TokenCache()
150{
151}
152
153
154//
155// Get a new, unused subservice id number.
156// Update the tracking file so we won't hand it out again (ever) within this cache.
157//
158uint32 TokenCache::allocateSubservice()
159{
160 putFile(path(lastSSIDFile), ++mLastSubservice);
161 return mLastSubservice;
162}
163
164
165//
166// A slightly souped-up UnixPlusPlus::makedir
167//
168void TokenCache::makedir(const char *path, int flags, mode_t mode, Owner owner)
169{
170 UnixPlusPlus::makedir(path, flags, mode);
171 switch(owner) {
172 case securityd:
173 // leave it alone; we own it alrady
174 break;
175 case tokend:
176 ::chown(path, tokendUid(), tokendGid());
177 break;
178 }
179}
180
181
182//
183// Make a cache entry from a valid tokenUid.
184// This will locate an existing entry or make a new one.
185//
186TokenCache::Token::Token(TokenCache &c, const string &tokenUid)
187 : Rooted(c.path(string(tokensDir) + "/" + tokenUid)), cache(c)
188{
189 cache.makedir(root(), O_CREAT, 0711, securityd);
fa7225c8
A
190 if ((mSubservice = int_cast<unsigned long, uint32>(getFile(path(ssidFile), 0)))) {
191 secinfo("tokencache", "found token \"%s\" ssid=%u", tokenUid.c_str(), mSubservice);
d8f41ccd
A
192 init(existing);
193 } else {
194 mSubservice = cache.allocateSubservice(); // allocate new, unique ssid...
195 putFile(path(ssidFile), mSubservice); // ... and save it in cache
fa7225c8 196 secinfo("tokencache", "new token \"%s\" ssid=%u", tokenUid.c_str(), mSubservice);
d8f41ccd
A
197 init(created);
198 }
199}
200
201
202//
203// Make a cache entry that is temporary and will never be reused.
204//
205TokenCache::Token::Token(TokenCache &c)
206 : cache(c)
207{
208 mSubservice = cache.allocateSubservice(); // new, unique id
209 char rootForm[30]; snprintf(rootForm, sizeof(rootForm),
fa7225c8 210 "%s/temporary:%u", tokensDir, mSubservice);
d8f41ccd
A
211 root(cache.path(rootForm));
212 cache.makedir(root(), O_CREAT | O_EXCL, 0711, securityd);
213 putFile(path(ssidFile), mSubservice); // ... and save it in cache
fa7225c8 214 secinfo("tokencache", "temporary token \"%s\" ssid=%u", rootForm, mSubservice);
d8f41ccd
A
215 init(temporary);
216}
217
218
219//
220// Common constructor setup code
221//
222void TokenCache::Token::init(Type type)
223{
224 mType = type;
225 cache.makedir(workPath(), O_CREAT, 0700, tokend);
226 cache.makedir(cachePath(), O_CREAT, 0700, tokend);
227}
228
229
230//
231// The Token destructor might clean or preen a bit, but shouldn't take
232// too long (or too much effort).
233//
234TokenCache::Token::~Token()
235{
236 if (type() == temporary)
fa7225c8 237 secinfo("tokencache", "@@@ should delete the cache directory here...");
d8f41ccd
A
238}
239
240
241//
242// Attributes of TokenCache::Tokens
243//
244string TokenCache::Token::workPath() const
245{
246 return path("Work");
247}
248
249string TokenCache::Token::cachePath() const
250{
251 return path("Cache");
252}
253
254
255string TokenCache::Token::printName() const
256{
257 return getFile(path("PrintName"), "");
258}
259
260void TokenCache::Token::printName(const string &name)
261{
262 putFile(path("PrintName"), name);
263}