Permalink
Browse files

Fixed crash in MRI 1.9.3.

  • Loading branch information...
1 parent 8da9140 commit 4ff2b0a425224d72e934750422de43392bfae997 @pwnall pwnall committed Dec 18, 2012
Showing with 268 additions and 257 deletions.
  1. +2 −0 .gitignore
  2. +10 −0 BUILD
  3. +4 −2 CHANGELOG
  4. +9 −9 Rakefile
  5. +51 −55 lib/smartcard/pcsc/card.rb
  6. +166 −166 lib/smartcard/pcsc/ffi_autogen.rb
  7. +26 −25 tasks/ffi_codegen.rb
View
@@ -1,4 +1,6 @@
.loadpath
+*.sw*
+
Makefile
doc
pkg
View
10 BUILD
@@ -75,3 +75,13 @@ Ubuntu (tested on 8.04, 8.10, 9.04 and 9.10):
* libpcsclite-dev (depends on libpcsclite or libpcsclite1)
* pcscd
* pcsc-tools
+
+=== Fedora
+
+The following packages should do the trick on Fedora (tested on 18):
+* ruby-devel
+* pcsc-lite
+* pcsc-lite-ccid
+* pcsc-lite-devel
+* pcsc-lite-openct
+* pcsc-tools
View
@@ -1,3 +1,5 @@
+v0.5.5. Fixed crash in MRI 1.9.3.
+
v0.5.4. Fixed ReaderStateQuery to work when the status has bits not defined in the PCSC header.
v0.5.3. Fixed buggy protocol number decoding logic.
@@ -38,7 +40,7 @@ v0.3.1. Fixed documentation for the new PcscException class.
v0.3.0. Added PcscException class used to wrap PC/SC exceptions.
-v0.2.3. Fixed minor bug in error string for PCSC::Card.transmit
+v0.2.3. Fixed minor bug in error string for PCSC::Card.transmit
v0.2.2. Fixed APDU exchange bugs on Windows
Restructured PCSC::IoRequest to allow PCI_ consts
@@ -51,7 +53,7 @@ v0.2.1. Added OSX Tiger support
v0.2.0. Added automatic builds
Rakefile for auto builds using echoe
- extconf.rb: hack to fix Windows makefiles
+ extconf.rb: hack to fix Windows makefiles
v0.1.2. Added Windows compatibility
*.c: restructured code so VC2005 likes it
View
@@ -1,26 +1,26 @@
require 'rubygems'
require 'echoe'
-require './tasks/ffi_codegen.rb'
+require './tasks/ffi_codegen.rb'
Echoe.new('smartcard') do |p|
p.project = 'smartcard' # rubyforge project
-
+
p.author = 'Victor Costan'
p.email = 'victor@costan.us'
p.summary = 'Interface with ISO 7816 smart cards.'
p.url = 'http://www.costan.us/smartcard'
- p.dependencies = ['ffi >=0.5.3',
- 'rubyzip >=0.9.1',
- 'zerg_support >=0.1.5']
- p.development_dependencies = ['echoe >=3.2',
- 'flexmock >=0.8.6']
-
+ p.dependencies = ['ffi >=1.2.0',
+ 'rubyzip >=0.9.9',
+ 'zerg_support >=0.1.6']
+ p.development_dependencies = ['echoe >=4.6.3',
+ 'flexmock >=1.2.0']
+
p.need_tar_gz = !Gem.win_platform?
p.need_zip = !Gem.win_platform?
p.clean_pattern += ['ext/**/*.manifest', 'ext/**/*_autogen.h']
p.rdoc_pattern =
- /^(lib|bin|tasks|ext)|^BUILD|^README|^CHANGELOG|^TODO|^LICENSE|^COPYING$/
+ /^(lib|bin|tasks|ext)|^BUILD|^README|^CHANGELOG|^TODO|^LICENSE|^COPYING$/
end
file 'lib/smartcard/pcsc/ffi_autogen.rb' => 'tasks/ffi_codegen.rb' do
View
@@ -8,8 +8,8 @@
# :nodoc: namespace
module Smartcard::PCSC
-
-
+
+
# Connects a smart-card in a PC/SC reader to the Ruby world.
class Card
# Establishes a connection to the card in a PC/SC reader.
@@ -19,10 +19,10 @@ class Card
# Args:
# context:: the Smartcard::PCSC::Context for the PC/SC resource manager
# reader_name:: friendly name of the reader to connect to; reader names can
- # be obtained from Smartcard::PCSC::Context#readers
+ # be obtained from Smartcard::PCSC::Context#readers
# sharing_mode:: whether a shared or exclusive lock will be requested on the
# reader; the possible values are +:shared+, +:exclusive+ and
- # +:direct+ (see the SCARD_SHARE_ constants in the PC/SC API)
+ # +:direct+ (see the SCARD_SHARE_ constants in the PC/SC API)
# preferred_protocols:: the desired communication protocol; the possible
# values are +:t0+, +:t1+, +:t15+, +:raw+, and +:any+
# (see the SCARD_PROTOCOL_ constants in the PC/SC API)
@@ -33,50 +33,46 @@ def initialize(context, reader_name, sharing_mode = :exclusive,
status = FFILib.card_connect context._handle, reader_name, sharing_mode,
preferred_protocols, handle_ptr, protocol_ptr
raise Smartcard::PCSC::Exception, status unless status == :success
-
+
@context = context
@sharing_mode = sharing_mode
@_handle = handle_ptr[:value]
set_protocol FFILib::PROTOCOLS[protocol_ptr[:value]]
end
-
+
# Updates internal buffers to reflect a change in the communication protocol.
#
# Args:
# protocol:: the protocol to change to; if invalid, the card's ATR will be
# used to guess a valid protocol
def set_protocol(protocol)
@protocol = protocol
-
+
case protocol
when :t0
- @send_pci = @recv_pci = FFILib::PCI_T0
+ @send_pci = FFILib::PCI_T0
when :t1
- @send_pci = @recv_pci = FFILib::PCI_T1
+ @send_pci = FFILib::PCI_T1
when :raw
- @send_pci = @recv_pci = FFILib::PCI_RAW
+ @send_pci = FFILib::PCI_RAW
else
reconnect sharing_mode, guess_protocol_from_atr, :leave
- return self
- end
-
- # Windows really doesn't like a receiving IoRequest.
- if FFI::Platform.windows? || FFI::Platform.mac?
- @recv_pci = nil
+ return self
end
+
self
end
private :set_protocol
-
+
# Reconnects to the smart-card, potentially using a different protocol.
#
# Args:
# sharing_mode:: whether a shared or exclusive lock will be requested on the
# reader; the possible values are +:shared+, +:exclusive+ and
- # +:direct+ (see the SCARD_SHARE_ constants in the PC/SC API)
+ # +:direct+ (see the SCARD_SHARE_ constants in the PC/SC API)
# preferred_protocols:: the desired communication protocol; the possible
# values are +:t0+, +:t1+, +:t15+, +:raw+, and +:any+
- # (see the SCARD_PROTOCOL_ constants in the PC/SC API)
+ # (see the SCARD_PROTOCOL_ constants in the PC/SC API)
# disposition:: what to do with the smart-card right before disconnecting;
# the possible values are +:leave+, +:reset+, +:unpower+, and
# +:eject+ (see the SCARD_*_CARD constants in the PC/SC API)
@@ -86,11 +82,11 @@ def reconnect(sharing_mode = :exclusive, preferred_protocols = :any,
status = FFILib.card_reconnect @_handle, sharing_mode,
preferred_protocols, disposition, protocol_ptr
raise Smartcard::PCSC::Exception, status unless status == :success
-
+
@sharing_mode = sharing_mode
set_protocol FFILib::Protocol[protocol_ptr[:value]]
end
-
+
# Disconnects from the smart-card.
#
# Future method calls on this object will raise PC/SC errors.
@@ -110,9 +106,9 @@ def disconnect(disposition = :leave)
# Starts a transaction, obtaining an exclusive lock on the smart-card.
def begin_transaction
status = FFILib.begin_transaction @_handle
- raise Smartcard::PCSC::Exception, status unless status == :success
+ raise Smartcard::PCSC::Exception, status unless status == :success
end
-
+
# Ends a transaction started with begin_transaction.
#
# The calling application must be the owner of the previously started
@@ -126,7 +122,7 @@ def end_transaction(disposition = :leave)
status = FFILib.end_transaction @_handle, disposition
raise Smartcard::PCSC::Exception, status unless status == :success
end
-
+
# Performs a block inside a transaction, with an exclusive smart-card lock.
#
# Args:
@@ -138,8 +134,8 @@ def transaction(disposition = :leave)
yield
end_transaction disposition
end
-
-
+
+
def [](attribute_name)
length_ptr = FFILib::WordPtr.new
status = FFILib.get_attrib @_handle, attribute_name, nil, length_ptr
@@ -150,13 +146,13 @@ def [](attribute_name)
status = FFILib.get_attrib @_handle, attribute_name, value_ptr,
length_ptr
raise Smartcard::PCSC::Exception, status unless status == :success
-
+
value_ptr.get_bytes 0, length_ptr[:value]
ensure
value_ptr.free
- end
+ end
end
-
+
# Sets the value of an attribute in the interface driver.
#
# The interface driver may not implement all possible attributes.
@@ -171,34 +167,34 @@ def []=(attribute_name, value)
begin
status = FFILib.set_attrib @_handle, attribute_name, value_ptr,
value.length
- raise Smartcard::PCSC::Exception, status unless status == :success
+ raise Smartcard::PCSC::Exception, status unless status == :success
value
ensure
- value_ptr.free
+ value_ptr.free
end
end
-
+
# Sends an APDU to the smart card, and returns the card's response.
#
# Args:
# send_data:: string containing the APDU bytes to be sent to the card
- # receive_buffer_size: the maximum number of bytes that can be received
+ # receive_buffer_size: the maximum number of bytes that can be received
def transmit(data, receive_buffer_size = 65546)
send_ptr = FFI::MemoryPointer.from_string data
recv_ptr = FFI::MemoryPointer.new receive_buffer_size
recv_size_ptr = FFILib::WordPtr.new
- recv_size_ptr[:value] = receive_buffer_size
+ recv_size_ptr[:value] = receive_buffer_size
begin
status = FFILib.transmit @_handle, @send_pci, send_ptr, data.length,
- @recv_pci, recv_ptr, recv_size_ptr
- raise Smartcard::PCSC::Exception, status unless status == :success
+ nil, recv_ptr, recv_size_ptr
+ raise Smartcard::PCSC::Exception, status unless status == :success
recv_ptr.get_bytes 0, recv_size_ptr[:value]
ensure
send_ptr.free
recv_ptr.free
- end
+ end
end
-
+
# Sends a interface driver command for the smart-card reader.
#
# This method is useful for creating client side reader drivers for functions
@@ -220,20 +216,20 @@ def control(code, data, receive_buffer_size = 4096)
send_ptr = FFI::MemoryPointer.from_string data
recv_ptr = FFI::MemoryPointer.new receive_buffer_size
recv_size_ptr = FFILib::WordPtr.new
- recv_size_ptr[:value] = receive_buffer_size
+ recv_size_ptr[:value] = receive_buffer_size
begin
status = FFILib.card_control @_handle, code, send_ptr, data.length,
recv_ptr, receive_buffer_size, recv_size_ptr
- raise Smartcard::PCSC::Exception, status unless status == :success
+ raise Smartcard::PCSC::Exception, status unless status == :success
recv_ptr.get_bytes 0, recv_size_ptr[:value]
ensure
send_ptr.free
recv_ptr.free
end
end
-
+
# Assorted information about this smart-card.
- #
+ #
# Returns a hash with the following keys:
# :state:: reader/card status, as a Set of symbols; the possible values are
# +:present+, +:swallowed+, +:absent+, +:specific+, and +:powered+
@@ -248,25 +244,25 @@ def info
protocol_ptr = FFILib::WordPtr.new
atr_ptr = FFI::MemoryPointer.new FFILib::Consts::MAX_ATR_SIZE
atr_length_ptr = FFILib::WordPtr.new
- atr_length_ptr[:value] = FFILib::Consts::MAX_ATR_SIZE
+ atr_length_ptr[:value] = FFILib::Consts::MAX_ATR_SIZE
begin
status = FFILib.card_status @_handle, nil, readers_length_ptr, state_ptr,
protocol_ptr, atr_ptr, atr_length_ptr
- raise Smartcard::PCSC::Exception, status unless status == :success
+ raise Smartcard::PCSC::Exception, status unless status == :success
readers_ptr = FFI::MemoryPointer.new :char, readers_length_ptr[:value]
begin
status = FFILib.card_status @_handle, readers_ptr, readers_length_ptr,
state_ptr, protocol_ptr, atr_ptr, atr_length_ptr
- raise Smartcard::PCSC::Exception, status unless status == :success
-
+ raise Smartcard::PCSC::Exception, status unless status == :success
+
state_word = state_ptr[:value]
state = Set.new
FFILib::CardState.to_h.each do |key, mask|
state << key if (state_word & mask) == mask && mask != 0
end
-
+
{ :readers => Context.decode_multi_string(readers_ptr),
:protocol => FFILib::PROTOCOLS[protocol_ptr[:value]],
:atr => atr_ptr.get_bytes(0, atr_length_ptr[:value]),
@@ -278,11 +274,11 @@ def info
atr_ptr.free
end
end
-
- # Returns the first valid protocol listed in the card's ATR.
+
+ # Returns the first valid protocol listed in the card's ATR.
def guess_protocol_from_atr
atr = info[:atr]
-
+
# NOTE: inspired from the following sources:
# http://en.wikipedia.org/wiki/Answer_to_reset
# http://www.atmel.com/dyn/resources/prod_documents/doc5025.pdf
@@ -295,13 +291,13 @@ def guess_protocol_from_atr
next_bits = (0...4).map { |j| (next_nibble >> j) & 1 }
next_bits.each { |bit| i += bit }
if next_bits[3] == 1 # TD byte was last, i is right on it
- protocols << (atr_bytes[i] & 0x0f)
+ protocols << (atr_bytes[i] & 0x0f)
else
break # No TD, no more bytes
end
end
- protocols.sort!
+ protocols.sort!
case protocols[0]
when 0
:t0
@@ -312,15 +308,15 @@ def guess_protocol_from_atr
end
end
private :guess_protocol_from_atr
-
+
# The low-level _SCARDHANDLE_ data.
#
# This should not be used by client code.
attr_reader :_handle
-
+
# The communication protocol in use with this smart-card.
attr_reader :protocol
-
+
# The sharing mode for this smart-card session. (:shared or :exclusive)
attr_reader :sharing_mode
end # class Smartcard::PCSC::Card
Oops, something went wrong.

0 comments on commit 4ff2b0a

Please sign in to comment.