]> git.saurik.com Git - apple/security.git/blob - securityd/src/tokencache.cpp
Security-59306.11.20.tar.gz
[apple/security.git] / securityd / src / tokencache.cpp
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>
33 #include <security_utilities/casts.h>
34 #include <pwd.h>
35 #include <grp.h>
36
37 using 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())
54 static const char configDir[] = "config";
55 static const char lastSSIDFile[] = "config/lastSSID";
56 static const char tokensDir[] = "tokens";
57
58 // relative to token directory (use token->path())
59 static const char ssidFile[] = "SSID";
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 //
67 static 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 = defaultValue;
74 sscanf(s.c_str(), "%lu", &value);
75 return value;
76 }
77 } catch (...) {
78 }
79 return defaultValue;
80 }
81
82 static string getFile(const string &path, const string &defaultValue)
83 {
84 try {
85 AutoFileDesc fd(path, O_RDONLY, FileDesc::modeMissingOk);
86 if (fd) {
87 string s; fd.readAll(s);
88 return s;
89 }
90 } catch (...) {
91 }
92 return defaultValue;
93 }
94
95
96 static void putFile(const string &path, uint32 value)
97 {
98 char buffer[64];
99 snprintf(buffer, sizeof(buffer), "%u\n", value);
100 AutoFileDesc(path, O_WRONLY | O_CREAT | O_TRUNC).writeAll(buffer);
101 }
102
103 static void putFile(const string &path, const string &value)
104 {
105 AutoFileDesc(path, O_WRONLY | O_CREAT | O_TRUNC).writeAll(value);
106 }
107
108
109 //
110 // The "rooted tree" utility class
111 //
112 void Rooted::root(const string &r)
113 {
114 assert(mRoot.empty()); // can't re-set this
115 mRoot = r;
116 }
117
118 string Rooted::path(const char *sub) const
119 {
120 if (sub == NULL)
121 return mRoot;
122 return mRoot + "/" + sub;
123 }
124
125
126 //
127 // Open a TokenCache.
128 // If the cache does not exist at the path given, initialize it.
129 // If that fails, throw an exception.
130 //
131 TokenCache::TokenCache(const char *where)
132 : Rooted(where), mLastSubservice(0)
133 {
134 makedir(root(), O_CREAT, 0711, securityd);
135 makedir(path(configDir), O_CREAT, 0700, securityd);
136 makedir(path(tokensDir), O_CREAT, 0711, securityd);
137
138 mLastSubservice = int_cast<ssize_t, uint32>(getFile(path(lastSSIDFile), 1));
139
140 // identify uid/gid for token daemons
141 struct passwd *pw = getpwnam(TOKEND_UID);
142 mTokendUid = pw ? pw->pw_uid : TOKEND_UID_FALLBACK;
143 struct group *gr = getgrnam(TOKEND_GID);
144 mTokendGid = gr ? gr->gr_gid : TOKEND_GID_FALLBACK;
145
146 secinfo("tokencache", "token cache rooted at %s (last ssid=%u, uid/gid=%d/%d)",
147 root().c_str(), mLastSubservice, mTokendUid, mTokendGid);
148 }
149
150 TokenCache::~TokenCache()
151 {
152 }
153
154
155 //
156 // Get a new, unused subservice id number.
157 // Update the tracking file so we won't hand it out again (ever) within this cache.
158 //
159 uint32 TokenCache::allocateSubservice()
160 {
161 putFile(path(lastSSIDFile), ++mLastSubservice);
162 return mLastSubservice;
163 }
164
165
166 //
167 // A slightly souped-up UnixPlusPlus::makedir
168 //
169 void TokenCache::makedir(const char *path, int flags, mode_t mode, Owner owner)
170 {
171 UnixPlusPlus::makedir(path, flags, mode);
172 switch(owner) {
173 case securityd:
174 // leave it alone; we own it alrady
175 break;
176 case tokend:
177 ::chown(path, tokendUid(), tokendGid());
178 break;
179 }
180 }
181
182
183 //
184 // Make a cache entry from a valid tokenUid.
185 // This will locate an existing entry or make a new one.
186 //
187 TokenCache::Token::Token(TokenCache &c, const string &tokenUid)
188 : Rooted(c.path(string(tokensDir) + "/" + tokenUid)), cache(c)
189 {
190 cache.makedir(root(), O_CREAT, 0711, securityd);
191 if ((mSubservice = int_cast<unsigned long, uint32>(getFile(path(ssidFile), 0)))) {
192 secinfo("tokencache", "found token \"%s\" ssid=%u", tokenUid.c_str(), mSubservice);
193 init(existing);
194 } else {
195 mSubservice = cache.allocateSubservice(); // allocate new, unique ssid...
196 putFile(path(ssidFile), mSubservice); // ... and save it in cache
197 secinfo("tokencache", "new token \"%s\" ssid=%u", tokenUid.c_str(), mSubservice);
198 init(created);
199 }
200 }
201
202
203 //
204 // Make a cache entry that is temporary and will never be reused.
205 //
206 TokenCache::Token::Token(TokenCache &c)
207 : cache(c)
208 {
209 mSubservice = cache.allocateSubservice(); // new, unique id
210 char rootForm[30]; snprintf(rootForm, sizeof(rootForm),
211 "%s/temporary:%u", tokensDir, mSubservice);
212 root(cache.path(rootForm));
213 cache.makedir(root(), O_CREAT | O_EXCL, 0711, securityd);
214 putFile(path(ssidFile), mSubservice); // ... and save it in cache
215 secinfo("tokencache", "temporary token \"%s\" ssid=%u", rootForm, mSubservice);
216 init(temporary);
217 }
218
219
220 //
221 // Common constructor setup code
222 //
223 void TokenCache::Token::init(Type type)
224 {
225 mType = type;
226 cache.makedir(workPath(), O_CREAT, 0700, tokend);
227 cache.makedir(cachePath(), O_CREAT, 0700, tokend);
228 }
229
230
231 //
232 // The Token destructor might clean or preen a bit, but shouldn't take
233 // too long (or too much effort).
234 //
235 TokenCache::Token::~Token()
236 {
237 if (type() == temporary)
238 secinfo("tokencache", "@@@ should delete the cache directory here...");
239 }
240
241
242 //
243 // Attributes of TokenCache::Tokens
244 //
245 string TokenCache::Token::workPath() const
246 {
247 return path("Work");
248 }
249
250 string TokenCache::Token::cachePath() const
251 {
252 return path("Cache");
253 }
254
255
256 string TokenCache::Token::printName() const
257 {
258 return getFile(path("PrintName"), "");
259 }
260
261 void TokenCache::Token::printName(const string &name)
262 {
263 putFile(path("PrintName"), name);
264 }