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