smartcard 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,84 @@
1
+ #include "pcsc.h"
2
+
3
+ VALUE cPcscIoRequest;
4
+
5
+ /* Custom free for Smartcard::PCSC::IoRequest. */
6
+ static void PCSC_IoRequest_free(SCARD_IO_REQUEST *_request) {
7
+ if(_request != NULL)
8
+ xfree(_request);
9
+ }
10
+
11
+ /* Custom allocation for Smartcard::PCSC::Card. Wraps a SCARD_IO_REQUEST. */
12
+ static VALUE PCSC_IoRequest_alloc(VALUE klass) {
13
+ SCARD_IO_REQUEST *request;
14
+
15
+ VALUE rbIoRequest = Data_Make_Struct(klass, SCARD_IO_REQUEST, NULL, PCSC_IoRequest_free, request);
16
+ return rbIoRequest;
17
+ }
18
+
19
+ /* :Document-method: protocol
20
+ * call-seq:
21
+ * io_request.protocol --> protocol
22
+ *
23
+ * The protocol of this instance.
24
+ *
25
+ * The returned protocol is a number, and should be checked against one of the Smartcard::PCSC::PROTOCOL_ constants.
26
+ */
27
+ static VALUE PCSC_IoRequest_get_protocol(VALUE self) {
28
+ SCARD_IO_REQUEST *request;
29
+ Data_Get_Struct(self, SCARD_IO_REQUEST, request);
30
+ if(request == NULL) return Qnil;
31
+
32
+ return UINT2NUM(request->dwProtocol);
33
+ }
34
+
35
+ /* :Document-method: protocol=
36
+ * call-seq:
37
+ * io_request.protocol = protocol
38
+ *
39
+ * Sets the protocol of this instance.
40
+ *
41
+ * +protocol+:: use one of the Smartcard::PCSC::PROTOCOL_ constants
42
+ */
43
+ static VALUE PCSC_IoRequest_set_protocol(VALUE self, VALUE rbProtocol) {
44
+ SCARD_IO_REQUEST *request;
45
+ Data_Get_Struct(self, SCARD_IO_REQUEST, request);
46
+ if(request == NULL) return self;
47
+
48
+ request->dwProtocol = NUM2UINT(rbProtocol);
49
+ return self;
50
+ }
51
+
52
+ #ifdef MAKE_RDOC_HAPPY
53
+ mSmartcard = rb_define_module("Smartcard");
54
+ mPcsc = rb_define_module_under(mSmartcard, "PCSC");
55
+ #endif
56
+
57
+ /* :Document-class: Smartcard::PCSC::IoRequest
58
+ * Protocol information used in Smartcard::PCSC::Card#transmit.
59
+ * Wraps a _SCARD_IO_REQUEST_ structure.
60
+ *
61
+ * I know the name is retarded, but it reflects the PC/SC name well. The choice makes sense given that this
62
+ * is an API meant for people familiar with the PC/SC specification.
63
+ */
64
+ void Init_PCSC_IoRequest() {
65
+ cPcscIoRequest = rb_define_class_under(mPcsc, "IoRequest", rb_cObject);
66
+ rb_define_alloc_func(cPcscIoRequest, PCSC_IoRequest_alloc);
67
+ rb_define_method(cPcscIoRequest, "protocol", PCSC_IoRequest_get_protocol, 0);
68
+ rb_define_method(cPcscIoRequest, "protocol=", PCSC_IoRequest_set_protocol, 1);
69
+ }
70
+
71
+ /* Retrieves the SCARD_IO_REQUEST wrapped into a Smartcard::PCSC::IoRequest instance. */
72
+ int _PCSC_IoRequest_lowlevel_get(VALUE rbIoRequest, SCARD_IO_REQUEST **io_request) {
73
+ if(TYPE(rbIoRequest) == T_NIL || TYPE(rbIoRequest) == T_FALSE) {
74
+ *io_request = NULL;
75
+ return 1;
76
+ }
77
+ if(TYPE(rbIoRequest) != T_DATA || RDATA(rbIoRequest)->dfree != (void (*)(void *))PCSC_IoRequest_free)
78
+ return 0;
79
+
80
+ SCARD_IO_REQUEST *request;
81
+ Data_Get_Struct(rbIoRequest, SCARD_IO_REQUEST, request);
82
+ *io_request = request;
83
+ return 1;
84
+ }
@@ -0,0 +1,10 @@
1
+ #include "pcsc.h"
2
+
3
+ void Init_smartcard_pcsc() {
4
+ Init_PCSC_Namespace();
5
+ Init_PCSC_ReaderStates();
6
+ Init_PCSC_IoRequest();
7
+ Init_PCSC_Context();
8
+ Init_PCSC_Card();
9
+ Init_PCSC_Consts();
10
+ }
@@ -0,0 +1,65 @@
1
+ #include <string.h>
2
+ #include "pcsc.h"
3
+
4
+ /* Converts a multi-string "str1\0str_2\0str3\0\0" into a Ruby array of Ruby strings. */
5
+ VALUE PCSC_Internal_multistring_to_ruby_array(char *mstr, size_t mstr_len) {
6
+ VALUE rbArray = rb_ary_new();
7
+ int i = 0;
8
+ for(; i < mstr_len; i++) {
9
+ if(mstr[i] == '\0') break;
10
+ int start_offset = i;
11
+ for(; i < mstr_len; i++)
12
+ if(mstr[i] == '\0') break;
13
+ VALUE rbString = rb_str_new(mstr + start_offset, i - start_offset);
14
+ rb_ary_push(rbArray, rbString);
15
+ }
16
+ return rbArray;
17
+ }
18
+
19
+ /* Constructs a multi-string "str1\0str_2\0str3\0\0". Takes nil, a string, or an array of strings.
20
+ * The returned buffer must be released with xfree.
21
+ * If false is returned, something went wrong and the method did not return a buffer.
22
+ */
23
+ int PCSC_Internal_ruby_strings_to_multistring(VALUE rbStrings, char **strings) {
24
+ /* nil -> NULL */
25
+ if(TYPE(rbStrings) == T_NIL || TYPE(rbStrings) == T_FALSE) {
26
+ *strings = NULL;
27
+ return 1;
28
+ }
29
+ /* string -> [string] */
30
+ if(TYPE(rbStrings) == T_STRING) {
31
+ size_t string_length = RSTRING(rbStrings)->len;
32
+ char *buffer = ALLOC_N(char, string_length + 2);
33
+ memcpy(buffer, RSTRING(rbStrings)->ptr, string_length);
34
+ buffer[string_length] = buffer[string_length + 1] = '\0';
35
+ *strings = buffer;
36
+ return 1;
37
+ }
38
+ /* array -> array */
39
+ if(TYPE(rbStrings) == T_ARRAY) {
40
+ /* compute buffer length */
41
+ size_t array_length = RARRAY(rbStrings)->len;
42
+ VALUE *array_elements = RARRAY(rbStrings)->ptr;
43
+ size_t buffer_length = 1; /* for the trailing '\0' */
44
+ int i = 0;
45
+ for(; i < array_length; i++) {
46
+ if(TYPE(array_elements[i]) != T_STRING)
47
+ return 0;
48
+ buffer_length += RSTRING(array_elements[i])->len + 1;
49
+ }
50
+
51
+ /* concatenate strings into buffer */
52
+ char *buffer = ALLOC_N(char, buffer_length);
53
+ for(buffer_length = 0, i = 0; i < array_length; i++) {
54
+ size_t string_length = RSTRING(array_elements[i])->len;
55
+ memcpy(buffer + buffer_length, RSTRING(array_elements[i])->ptr, string_length);
56
+ buffer[buffer_length] = '\0';
57
+ buffer_length += string_length + 1;
58
+ }
59
+ buffer[buffer_length] = '\0';
60
+ *strings = buffer;
61
+ return 1;
62
+ }
63
+
64
+ return 0;
65
+ }
@@ -0,0 +1,18 @@
1
+ #include "pcsc.h"
2
+
3
+ VALUE mSmartcard;
4
+ VALUE mPcsc;
5
+
6
+ /* :Document-class: Smartcard::PCSC
7
+ * Bindings to the PC/SC Smartcard API.
8
+ *
9
+ */
10
+ static void Init_PCSC() {
11
+ mPcsc = rb_define_module_under(mSmartcard, "PCSC");
12
+ }
13
+
14
+ void Init_PCSC_Namespace() {
15
+ mSmartcard = rb_define_module("Smartcard");
16
+ Init_PCSC();
17
+ }
18
+
@@ -0,0 +1,313 @@
1
+ #include "pcsc.h"
2
+
3
+ VALUE cPcscReaderStates;
4
+
5
+ /* Wraps an array of SCARD_READERSTATE elements. */
6
+ struct PCSCReaderStates {
7
+ size_t states_count;
8
+ SCARD_READERSTATE *states;
9
+ };
10
+
11
+ /* Custom free for Smartcard::PCSC::ReaderStates. Also releases the referenced buffers (for the reader names). */
12
+ static void PCSC_ReaderStates_free(struct PCSCReaderStates *_states) {
13
+ if(_states != NULL) {
14
+ if(_states->states != NULL) {
15
+ size_t i = 0;
16
+ for(; i < _states->states_count; i++) {
17
+ if(_states->states[i].szReader != NULL)
18
+ xfree((char *)_states->states[i].szReader);
19
+ }
20
+ xfree(_states->states);
21
+ }
22
+ xfree(_states);
23
+ }
24
+ }
25
+
26
+ /* Custom allocation for Smartcard::PCSC::ReaderStates. Wraps a reference to an array of SCARD_READERSTATE. */
27
+ static VALUE PCSC_ReaderStates_alloc(VALUE klass) {
28
+ struct PCSCReaderStates *states;
29
+
30
+ VALUE rbReaderStates = Data_Make_Struct(klass, struct PCSCReaderStates, NULL, PCSC_ReaderStates_free, states);
31
+ states->states_count = 0;
32
+ states->states = NULL;
33
+ return rbReaderStates;
34
+ }
35
+
36
+ /* :Document-method: new
37
+ * call-seq:
38
+ * new(num_states) --> reader_states
39
+ *
40
+ * Creates an array of +num_states+ reader state elements.
41
+ * The states are unusable until they are assigned reader names by calling ReaderStates#set_reader_name_of.
42
+ */
43
+ static VALUE PCSC_ReaderStates_initialize(VALUE self, VALUE rbNumStates) {
44
+ struct PCSCReaderStates *states;
45
+ Data_Get_Struct(self, struct PCSCReaderStates, states);
46
+
47
+ size_t states_count = NUM2UINT(rbNumStates);
48
+ if(states_count > 0) {
49
+ states->states = ALLOC_N(SCARD_READERSTATE, states_count);
50
+ if(states->states != NULL) {
51
+ states->states_count = states_count;
52
+ size_t i = 0;
53
+ for(; i < states_count; i++) {
54
+ states->states[i].szReader = NULL;
55
+ states->states[i].dwCurrentState = SCARD_STATE_UNAWARE;
56
+ }
57
+ }
58
+ }
59
+ return self;
60
+ }
61
+
62
+ static int _validate_readerstates_args(VALUE rbReaderStates, VALUE rbIndex, struct PCSCReaderStates **states, size_t *index) {
63
+ Data_Get_Struct(rbReaderStates, struct PCSCReaderStates, *states);
64
+ if(*states == NULL) return 0;
65
+
66
+ *index = NUM2UINT(rbIndex);
67
+ if(*index >= (*states)->states_count) {
68
+ rb_raise(rb_eIndexError, "index %u is invalid (states array has %u elements)", *index, (*states)->states_count);
69
+ return 0;
70
+ }
71
+
72
+ return 1;
73
+ }
74
+
75
+ /* :Document-method: current_state_of
76
+ * call-seq:
77
+ * current_state_of(index) --> current_state
78
+ *
79
+ * The current state (_dwCurrentState_ in PC/SC) in the <tt>index</tt>th reader state element.
80
+ * Smartcard::PCSC::Context#get_status_change blocks as long as the reader state equals this value.
81
+ *
82
+ * The returned state is a bitfield; the bits are defined in the Smartcard::PCSC::STATE_ constants.
83
+ *
84
+ * +index+:: the 0-based index of the reader state element to be queried
85
+ */
86
+ static VALUE PCSC_ReaderStates_current_state_of(VALUE self, VALUE rbIndex) {
87
+ struct PCSCReaderStates *states;
88
+ size_t index;
89
+ if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
90
+ return Qnil;
91
+
92
+ return UINT2NUM(states->states[index].dwCurrentState);
93
+ }
94
+
95
+ /* :Document-method: event_state_of
96
+ * call-seq:
97
+ * event_state_of(index) --> event_state
98
+ *
99
+ * The event state (_dwEventState_ in PC/SC) in the <tt>index</tt>th reader state element.
100
+ * Smartcard::PCSC::Context#get_status_change stores the updated reader state in this value.
101
+ *
102
+ * The returned state is a bitfield; the bits are defined in the Smartcard::PCSC::STATE_ constants.
103
+ *
104
+ * +index+:: the 0-based index of the reader state element to be queried
105
+ */
106
+ static VALUE PCSC_ReaderStates_event_state_of(VALUE self, VALUE rbIndex) {
107
+ struct PCSCReaderStates *states;
108
+ size_t index;
109
+ if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
110
+ return Qnil;
111
+
112
+ return UINT2NUM(states->states[index].dwEventState);
113
+ }
114
+
115
+ /* :Document-method: set_current_state_of!
116
+ * call-seq:
117
+ * set_current_state_of!(index, current_state) --> self
118
+ *
119
+ * Sets the current state (_dwCurrentState_ in PC/SC) in the <tt>index</tt>th reader state element.
120
+ * Smartcard::PCSC::Context#get_status_change blocks as long as the reader state equals this value.
121
+ *
122
+ *
123
+ * +index+:: the 0-based index of the reader state element to be modified
124
+ * +current_state+:: a bitfield; the bits are defined in the Smartcard::PCSC::STATE_ constants.
125
+ */
126
+ static VALUE PCSC_ReaderStates_set_current_state_of(VALUE self, VALUE rbIndex, VALUE rbCurrentState) {
127
+ struct PCSCReaderStates *states;
128
+ size_t index;
129
+ if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
130
+ return self;
131
+
132
+ states->states[index].dwCurrentState = NUM2UINT(rbCurrentState);
133
+ return self;
134
+ }
135
+
136
+ /* :Document-method: set_event_state_of!
137
+ * call-seq:
138
+ * set_event_state_of!(index, event_state) --> self
139
+ *
140
+ * Sets the event state (_dwEventState_ in PC/SC) in the <tt>index</tt>th reader state element.
141
+ * Smartcard::PCSC::Context#get_status_change stores the updated reader state in this value.
142
+ *
143
+ * +index+:: the 0-based index of the reader state element to be modified
144
+ * +event_state+:: a bitfield; the bits are defined in the Smartcard::PCSC::STATE_ constants.
145
+ */
146
+ static VALUE PCSC_ReaderStates_set_event_state_of(VALUE self, VALUE rbIndex, VALUE rbEventState) {
147
+ struct PCSCReaderStates *states;
148
+ size_t index;
149
+ if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
150
+ return self;
151
+
152
+ states->states[index].dwEventState = NUM2UINT(rbEventState);
153
+ return self;
154
+ }
155
+
156
+ /* :Document-method: atr_of
157
+ * call-seq:
158
+ * atr_of(index) --> atr
159
+ *
160
+ * The card ATR string in the <tt>index</tt>th reader state element.
161
+ * Smartcard::PCSC::Context#get_status_change stores the updated ATR string in this value.
162
+ *
163
+ * The returned ATR bytes are wrapped into a string. (don't complain, it's a low-level API)
164
+ *
165
+ * +index+:: the 0-based index of the reader state element to be queried
166
+ */
167
+ static VALUE PCSC_ReaderStates_atr_of(VALUE self, VALUE rbIndex) {
168
+ struct PCSCReaderStates *states;
169
+ size_t index;
170
+ if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
171
+ return Qnil;
172
+
173
+ return rb_str_new((char *)states->states[index].rgbAtr, states->states[index].cbAtr);
174
+ }
175
+
176
+ /* :Document-method: set_atr_of!
177
+ * call-seq:
178
+ * set_atr_of!(index, atr) --> self
179
+ *
180
+ * Sets the card ATR string in the <tt>index</tt>th reader state element.
181
+ * Smartcard::PCSC::Context#get_status_change stores the updated ATR string in this value.
182
+ *
183
+ * +index+:: the 0-based index of the reader state element to be modified
184
+ * +atr+:: ATR bytes wrapped into a string (low-level API, remember?)
185
+ */
186
+ static VALUE PCSC_ReaderStates_set_atr_of(VALUE self, VALUE rbIndex, VALUE rbAtr) {
187
+ struct PCSCReaderStates *states;
188
+ size_t index;
189
+ if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
190
+ return self;
191
+
192
+ VALUE rbFinalAtr = rb_check_string_type(rbAtr);
193
+ if(NIL_P(rbFinalAtr))
194
+ return self;
195
+
196
+ if(RSTRING(rbFinalAtr)->len > MAX_ATR_SIZE) {
197
+ rb_raise(rb_eArgError, "given ATR is too long (%d characters given; can do at most MAX_ATR_SIZE = %d)", RSTRING(rbFinalAtr)->len, MAX_ATR_SIZE);
198
+ return self;
199
+ }
200
+
201
+ states->states[index].cbAtr = RSTRING(rbAtr)->len;
202
+ memcpy(states->states[index].rgbAtr, RSTRING(rbAtr)->ptr, states->states[index].cbAtr);
203
+ return self;
204
+ }
205
+
206
+ /* :Document-method: reader_name_of
207
+ * call-seq:
208
+ * reader_name_of(index) --> reader_name
209
+ *
210
+ * The name of the reader whose status is represented in the <tt>index</tt>th reader state element.
211
+ * Smartcard::PCSC::Context#get_status_change reads this value, and never updates it.
212
+ *
213
+ * +index+:: the 0-based index of the reader state element to be queried
214
+ */
215
+ static VALUE PCSC_ReaderStates_reader_name_of(VALUE self, VALUE rbIndex) {
216
+ struct PCSCReaderStates *states;
217
+ size_t index;
218
+ if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
219
+ return Qnil;
220
+
221
+ return rb_str_new2(states->states[index].szReader);
222
+ }
223
+
224
+ /* :Document-method: set_reader_name_of!
225
+ * call-seq:
226
+ * set_reader_name_of!(index, reader_name) --> self
227
+ *
228
+ * The name of the reader whose status is represented in the <tt>index</tt>th reader state element.
229
+ * Smartcard::PCSC::Context#get_status_change reads this value, and never updates it.
230
+ *
231
+ * +index+:: the 0-based index of the reader state element to be modified
232
+ * +reader_name+:: a string-like object containing the reader name to be associated with the state element
233
+ */
234
+ static VALUE PCSC_ReaderStates_set_reader_name_of(VALUE self, VALUE rbIndex, VALUE rbReaderName) {
235
+ struct PCSCReaderStates *states;
236
+ size_t index;
237
+ if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
238
+ return self;
239
+
240
+ VALUE rbFinalReaderName = rb_check_string_type(rbReaderName);
241
+ if(NIL_P(rbFinalReaderName))
242
+ return self;
243
+
244
+ size_t reader_name_length = RSTRING(rbFinalReaderName)->len;
245
+ if(states->states[index].szReader != NULL)
246
+ xfree((char *)states->states[index].szReader);
247
+ states->states[index].szReader = ALLOC_N(char, reader_name_length + 1);
248
+ if(states->states[index].szReader != NULL) {
249
+ memcpy((char *)states->states[index].szReader, RSTRING(rbFinalReaderName)->ptr, reader_name_length);
250
+ ((char *)states->states[index].szReader)[reader_name_length] = '\0';
251
+ }
252
+ return self;
253
+ }
254
+
255
+ /* :Document-method: acknowledge_events!
256
+ * call-seq:
257
+ * acknowledge_events!() --> self
258
+ *
259
+ * Mass-assigns +current_state+ to +event_state+ for each reader state element.
260
+ * Useful to acknowledge all the status changed communicated after a call to Smartcard::PCSC::Context#get_status_change
261
+ * (and thus prepare for a new call).
262
+ */
263
+ static VALUE PCSC_ReaderStates_acknowledge_events(VALUE self) {
264
+ struct PCSCReaderStates *states;
265
+ Data_Get_Struct(self, struct PCSCReaderStates, states);
266
+ if(states != NULL) {
267
+ size_t i = 0;
268
+ for(; i < states->states_count; i++)
269
+ states->states[i].dwCurrentState = states->states[i].dwEventState;
270
+ }
271
+ return self;
272
+ }
273
+
274
+ #ifdef MAKE_RDOC_HAPPY
275
+ mSmartcard = rb_define_module("Smartcard");
276
+ mPcsc = rb_define_module_under(mSmartcard, "PCSC");
277
+ #endif
278
+
279
+ /* :Document-class: Smartcard::PCSC::ReaderStates
280
+ * Tracks reader status information, and is used in Smartcard::PCSC::Context#get_status_change.
281
+ * Wraps an array of <i>SCARD_READERSTATE</i> structures.
282
+ */
283
+ void Init_PCSC_ReaderStates() {
284
+ cPcscReaderStates = rb_define_class_under(mPcsc, "ReaderStates", rb_cObject);
285
+ rb_define_alloc_func(cPcscReaderStates, PCSC_ReaderStates_alloc);
286
+ rb_define_method(cPcscReaderStates, "initialize", PCSC_ReaderStates_initialize, 1);
287
+ rb_define_method(cPcscReaderStates, "current_state_of", PCSC_ReaderStates_current_state_of, 1);
288
+ rb_define_method(cPcscReaderStates, "set_current_state_of!", PCSC_ReaderStates_set_current_state_of, 2);
289
+ rb_define_method(cPcscReaderStates, "event_state_of", PCSC_ReaderStates_event_state_of, 1);
290
+ rb_define_method(cPcscReaderStates, "set_event_state_of!", PCSC_ReaderStates_set_event_state_of, 2);
291
+ rb_define_method(cPcscReaderStates, "reader_name_of", PCSC_ReaderStates_reader_name_of, 1);
292
+ rb_define_method(cPcscReaderStates, "set_reader_name_of!", PCSC_ReaderStates_set_reader_name_of, 2);
293
+ rb_define_method(cPcscReaderStates, "atr_of", PCSC_ReaderStates_atr_of, 1);
294
+ rb_define_method(cPcscReaderStates, "set_atr_of!", PCSC_ReaderStates_set_atr_of, 2);
295
+ rb_define_method(cPcscReaderStates, "acknowledge_events!", PCSC_ReaderStates_acknowledge_events, 0);
296
+ }
297
+
298
+ /* Retrieves the SCARD_READERSTATE array wrapped into a Smartcard::PCSC::ReaderStates instance. */
299
+ int _PCSC_ReaderStates_lowlevel_get(VALUE rbReaderStates, SCARD_READERSTATE **reader_states, size_t *reader_states_count) {
300
+ if(TYPE(rbReaderStates) == T_NIL || TYPE(rbReaderStates) == T_FALSE) {
301
+ *reader_states = NULL;
302
+ *reader_states_count = 0;
303
+ return 1;
304
+ }
305
+ if(TYPE(rbReaderStates) != T_DATA || RDATA(rbReaderStates)->dfree != (void (*)(void *))PCSC_ReaderStates_free)
306
+ return 0;
307
+
308
+ struct PCSCReaderStates *states;
309
+ Data_Get_Struct(rbReaderStates, struct PCSCReaderStates, states);
310
+ *reader_states = states->states;
311
+ *reader_states_count = states->states_count;
312
+ return 1;
313
+ }