210 lines
5.8 KiB
Go
210 lines
5.8 KiB
Go
// +build !windows,!darwin
|
|
|
|
package scard
|
|
|
|
// #cgo pkg-config: libpcsclite
|
|
// #include <stdlib.h>
|
|
// #include <winscard.h>
|
|
//
|
|
// LONG wrapSCardGetStatusChange(SCARDCONTEXT ctx, DWORD timeout, SCARD_READERSTATE *states, DWORD nstates) {
|
|
// return SCardGetStatusChange(ctx, timeout, states, nstates);
|
|
// }
|
|
//
|
|
import "C"
|
|
|
|
import (
|
|
"unsafe"
|
|
)
|
|
|
|
func (e Error) Error() string {
|
|
return "scard: " + C.GoString(C.pcsc_stringify_error(C.LONG(e)))
|
|
}
|
|
|
|
// Version returns the libpcsclite version string
|
|
func Version() string {
|
|
return C.PCSCLITE_VERSION_NUMBER
|
|
}
|
|
|
|
func scardEstablishContext(scope Scope, reserved1, reserved2 uintptr) (uintptr, Error) {
|
|
var ctx C.SCARDCONTEXT
|
|
r := C.SCardEstablishContext(C.DWORD(scope), C.LPCVOID(reserved1), C.LPCVOID(reserved2), &ctx)
|
|
return uintptr(ctx), Error(r)
|
|
}
|
|
|
|
func scardIsValidContext(ctx uintptr) Error {
|
|
r := C.SCardIsValidContext(C.SCARDCONTEXT(ctx))
|
|
return Error(r)
|
|
}
|
|
|
|
func scardCancel(ctx uintptr) Error {
|
|
r := C.SCardCancel(C.SCARDCONTEXT(ctx))
|
|
return Error(r)
|
|
}
|
|
|
|
func scardReleaseContext(ctx uintptr) Error {
|
|
r := C.SCardReleaseContext(C.SCARDCONTEXT(ctx))
|
|
return Error(r)
|
|
}
|
|
|
|
func scardListReaders(ctx uintptr, groups, buf unsafe.Pointer, bufLen uint32) (uint32, Error) {
|
|
dwBufLen := C.DWORD(bufLen)
|
|
r := C.SCardListReaders(C.SCARDCONTEXT(ctx), (C.LPCSTR)(groups), (C.LPSTR)(buf), &dwBufLen)
|
|
return uint32(dwBufLen), Error(r)
|
|
}
|
|
|
|
func scardListReaderGroups(ctx uintptr, buf unsafe.Pointer, bufLen uint32) (uint32, Error) {
|
|
dwBufLen := C.DWORD(bufLen)
|
|
r := C.SCardListReaderGroups(C.SCARDCONTEXT(ctx), (C.LPSTR)(buf), &dwBufLen)
|
|
return uint32(dwBufLen), Error(r)
|
|
}
|
|
|
|
func scardGetStatusChange(ctx uintptr, timeout uint32, states []scardReaderState) Error {
|
|
r := C.wrapSCardGetStatusChange(C.SCARDCONTEXT(ctx), C.DWORD(timeout), (*C.SCARD_READERSTATE)(unsafe.Pointer(&states[0])), C.DWORD(len(states)))
|
|
return Error(r)
|
|
}
|
|
|
|
func scardConnect(ctx uintptr, reader unsafe.Pointer, shareMode ShareMode, proto Protocol) (uintptr, Protocol, Error) {
|
|
var handle C.SCARDHANDLE
|
|
var activeProto C.DWORD
|
|
|
|
r := C.SCardConnect(C.SCARDCONTEXT(ctx), C.LPCSTR(reader), C.DWORD(shareMode), C.DWORD(proto), &handle, &activeProto)
|
|
|
|
return uintptr(handle), Protocol(activeProto), Error(r)
|
|
}
|
|
|
|
func scardDisconnect(card uintptr, d Disposition) Error {
|
|
r := C.SCardDisconnect(C.SCARDHANDLE(card), C.DWORD(d))
|
|
return Error(r)
|
|
}
|
|
|
|
func scardReconnect(card uintptr, mode ShareMode, proto Protocol, disp Disposition) (Protocol, Error) {
|
|
var activeProtocol C.DWORD
|
|
r := C.SCardReconnect(C.SCARDHANDLE(card), C.DWORD(mode), C.DWORD(proto), C.DWORD(disp), &activeProtocol)
|
|
return Protocol(activeProtocol), Error(r)
|
|
}
|
|
|
|
func scardBeginTransaction(card uintptr) Error {
|
|
r := C.SCardBeginTransaction(C.SCARDHANDLE(card))
|
|
return Error(r)
|
|
}
|
|
|
|
func scardEndTransaction(card uintptr, disp Disposition) Error {
|
|
r := C.SCardEndTransaction(C.SCARDHANDLE(card), C.DWORD(disp))
|
|
return Error(r)
|
|
}
|
|
|
|
func scardCardStatus(card uintptr, readerBuf []byte, atrBuf []byte) (uint32, State, Protocol, uint32, Error) {
|
|
var readerLen = C.DWORD(len(readerBuf))
|
|
var state, proto C.DWORD
|
|
var atrLen = C.DWORD(len(atrBuf))
|
|
|
|
r := C.SCardStatus(C.SCARDHANDLE(card), (C.LPSTR)(unsafe.Pointer(&readerBuf[0])), &readerLen, &state, &proto, (*C.BYTE)(&atrBuf[0]), &atrLen)
|
|
|
|
return uint32(readerLen), State(state), Protocol(proto), uint32(atrLen), Error(r)
|
|
}
|
|
|
|
func scardTransmit(card uintptr, proto Protocol, cmd []byte, rsp []byte) (uint32, Error) {
|
|
var sendpci C.SCARD_IO_REQUEST
|
|
var recvpci C.SCARD_IO_REQUEST
|
|
var rspLen = C.DWORD(len(rsp))
|
|
|
|
switch proto {
|
|
case ProtocolT0, ProtocolT1:
|
|
sendpci.dwProtocol = C.ulong(proto)
|
|
default:
|
|
panic("unknown protocol")
|
|
}
|
|
sendpci.cbPciLength = C.sizeof_SCARD_IO_REQUEST
|
|
|
|
r := C.SCardTransmit(C.SCARDHANDLE(card), &sendpci, (*C.BYTE)(&cmd[0]), C.DWORD(len(cmd)), &recvpci, (*C.BYTE)(&rsp[0]), &rspLen)
|
|
|
|
return uint32(rspLen), Error(r)
|
|
}
|
|
|
|
func scardControl(card uintptr, ioctl uint32, in, out []byte) (uint32, Error) {
|
|
var ptrIn C.LPCVOID
|
|
var outLen = C.DWORD(len(out))
|
|
|
|
if len(in) != 0 {
|
|
ptrIn = C.LPCVOID(unsafe.Pointer(&in[0]))
|
|
}
|
|
|
|
r := C.SCardControl(C.SCARDHANDLE(card), C.DWORD(ioctl), ptrIn, C.DWORD(len(in)), (C.LPVOID)(unsafe.Pointer(&out[0])), C.DWORD(len(out)), &outLen)
|
|
return uint32(outLen), Error(r)
|
|
}
|
|
|
|
func scardGetAttrib(card uintptr, id Attrib, buf []byte) (uint32, Error) {
|
|
var ptr C.LPBYTE
|
|
|
|
if len(buf) != 0 {
|
|
ptr = C.LPBYTE(unsafe.Pointer(&buf[0]))
|
|
}
|
|
|
|
bufLen := C.DWORD(len(buf))
|
|
r := C.SCardGetAttrib(C.SCARDHANDLE(card), C.DWORD(id), ptr, &bufLen)
|
|
|
|
return uint32(bufLen), Error(r)
|
|
}
|
|
|
|
func scardSetAttrib(card uintptr, id Attrib, buf []byte) Error {
|
|
r := C.SCardSetAttrib(C.SCARDHANDLE(card), C.DWORD(id), (*C.BYTE)(unsafe.Pointer(&buf[0])), C.DWORD(len(buf)))
|
|
return Error(r)
|
|
}
|
|
|
|
type strbuf []byte
|
|
|
|
func encodestr(s string) (strbuf, error) {
|
|
buf := strbuf(s + "\x00")
|
|
return buf, nil
|
|
}
|
|
|
|
func decodestr(buf strbuf) string {
|
|
if len(buf) == 0 {
|
|
return ""
|
|
}
|
|
|
|
if buf[len(buf)-1] == 0 {
|
|
buf = buf[:len(buf)-1]
|
|
}
|
|
|
|
return string(buf)
|
|
}
|
|
|
|
type scardReaderState struct {
|
|
szReader uintptr
|
|
pvUserData uintptr
|
|
dwCurrentState uintptr
|
|
dwEventState uintptr
|
|
cbAtr uintptr
|
|
rgbAtr [33]byte
|
|
}
|
|
|
|
var pinned = map[string]*strbuf{}
|
|
|
|
func (rs *ReaderState) toSys() (scardReaderState, error) {
|
|
var sys scardReaderState
|
|
|
|
creader, err := encodestr(rs.Reader)
|
|
if err != nil {
|
|
return scardReaderState{}, err
|
|
}
|
|
pinned[rs.Reader] = &creader
|
|
sys.szReader = uintptr(creader.ptr())
|
|
sys.dwCurrentState = uintptr(rs.CurrentState)
|
|
sys.cbAtr = uintptr(len(rs.Atr))
|
|
for i, v := range rs.Atr {
|
|
sys.rgbAtr[i] = byte(v)
|
|
}
|
|
return sys, nil
|
|
}
|
|
|
|
func (rs *ReaderState) update(sys *scardReaderState) {
|
|
rs.EventState = StateFlag(sys.dwEventState)
|
|
if sys.cbAtr > 0 {
|
|
rs.Atr = make([]byte, int(sys.cbAtr))
|
|
for i := 0; i < int(sys.cbAtr); i++ {
|
|
rs.Atr[i] = byte(sys.rgbAtr[i])
|
|
}
|
|
}
|
|
}
|