]> git.saurik.com Git - apple/securityd.git/blob - src/pcsc++.cpp
99d9655e515786c79f2e19dfc26d9ada236c6425
[apple/securityd.git] / src / pcsc++.cpp
1 /*
2 * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25
26
27 //
28 // pcsc++ - PCSC client interface layer in C++
29 //
30 #include "pcsc++.h"
31 #include <security_utilities/debugging.h>
32
33
34 namespace Security {
35 namespace PCSC {
36
37
38 //
39 // Internal utilities
40 //
41 static void decode(vector<string> &names, const char *buffer, size_t size)
42 {
43 names.clear();
44 for (size_t pos = 0; pos < size - 1; ) {
45 size_t len = strlen(buffer + pos);
46 names.push_back(string(buffer + pos, len));
47 pos += len + 1;
48 }
49 }
50
51 inline void decode(vector<string> &names, const vector<char> &buffer, size_t size)
52 {
53 decode(names, &buffer[0], size);
54 }
55
56
57 //
58 // PCSC domain errors
59 //
60 Error::Error(long err) : error(err)
61 {
62 IFDEBUG(debugDiagnose(this));
63 }
64
65
66 const char *Error::what() const throw ()
67 {
68 return pcsc_stringify_error(error);
69 }
70
71
72 void Error::throwMe(long err)
73 {
74 throw Error(err);
75 }
76
77
78 OSStatus Error::osStatus() const
79 {
80 return -1; //@@@ preliminary
81 }
82
83 int Error::unixError() const
84 {
85 return EINVAL; //@@@ preliminary
86 }
87
88 #if !defined(NDEBUG)
89 void Error::debugDiagnose(const void *id) const
90 {
91 secdebug("exception", "%p PCSC::Error %s (%ld) osStatus %ld",
92 id, pcsc_stringify_error(error), error, osStatus());
93 }
94 #endif //NDEBUG
95
96
97 //
98 // PodWrappers
99 //
100 void ReaderState::set(const char *name, unsigned long known)
101 {
102 clearPod();
103 szReader = name;
104 pvUserData = NULL;
105 dwCurrentState = known;
106 }
107
108
109 void ReaderState::lastKnown(unsigned long s)
110 {
111 // clear out CHANGED and UNAVAILABLE
112 dwCurrentState = s & ~(SCARD_STATE_CHANGED | SCARD_STATE_UNAVAILABLE);
113 }
114
115
116 #if defined(DEBUGDUMP)
117
118 void ReaderState::dump()
119 {
120 Debug::dump("reader(%s) state=0x%lx events=0x%lx",
121 szReader ? szReader : "(null)", dwCurrentState, dwEventState);
122 Debug::dumpData(" ATR", rgbAtr, cbAtr);
123 }
124
125 #endif //DEBUGDUMP
126
127
128 //
129 // Session objects
130 //
131 Session::Session()
132 : mIsOpen(false)
133 {
134 open();
135 }
136
137
138 Session::~Session()
139 {
140 if (mIsOpen)
141 Error::check(SCardReleaseContext(mContext));
142 }
143
144
145 //
146 // (Re)establish PCSC context.
147 // Don't fail on SCARD_F_INTERNAL_ERROR (pcscd not running).
148 void Session::open()
149 {
150 if (!mIsOpen) {
151 try {
152 Error::check(::SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &mContext));
153 mIsOpen = true;
154 secdebug("pcsc", "context opened");
155 } catch (const Error &err) {
156 if (err.error == long(SCARD_F_INTERNAL_ERROR)) {
157 secdebug("pcsc", "context not opened");
158 return;
159 }
160 }
161 }
162 }
163
164
165 bool Session::check(long rc)
166 {
167 switch (rc) {
168 case SCARD_S_SUCCESS:
169 return true; // got reader(s), call succeeded
170 case SCARD_E_READER_UNAVAILABLE:
171 return false; // no readers, but don't treat as error
172 default:
173 Error::throwMe(rc);
174 return false; // placebo
175 }
176 }
177
178
179 void Session::listReaders(vector<string> &readers, const char *groups)
180 {
181 mReaderBuffer.resize(1000); //@@@ preliminary hack
182 unsigned long size = mReaderBuffer.size();
183 if (check(::SCardListReaders(mContext, groups, &mReaderBuffer[0], &size)))
184 decode(readers, mReaderBuffer, size);
185 else
186 readers.clear(); // treat as success (returning zero readers)
187 }
188
189
190 //
191 // Reader status check
192 //
193 void Session::statusChange(ReaderState *readers, unsigned int nReaders, long timeout)
194 {
195 if (nReaders == 0)
196 return; // no readers, no foul
197 check(::SCardGetStatusChange(mContext, timeout, readers, nReaders));
198 }
199
200
201 //
202 // PCSC Card objects
203 //
204 Card::Card()
205 : mIsOpen(false)
206 {
207 }
208
209 Card::~Card()
210 {
211 }
212
213 void Card::open(Session &session, const char *reader,
214 unsigned long share, unsigned long protocols)
215 {
216 Error::check(::SCardConnect(session.mContext,
217 reader, share, protocols, &mHandle, &mProtocol));
218 mIsOpen = true;
219 }
220
221 void Card::close(unsigned long disposition)
222 {
223 if (mIsOpen) {
224 Error::check(::SCardDisconnect(mHandle, disposition));
225 mIsOpen = false;
226 }
227 }
228
229
230 } // namespace PCSC
231 } // namespace Security