220 lines
6.7 KiB
Go
220 lines
6.7 KiB
Go
|
package scard
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"syscall"
|
||
|
"unsafe"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
modwinscard = syscall.NewLazyDLL("winscard.dll")
|
||
|
|
||
|
procEstablishContext = modwinscard.NewProc("SCardEstablishContext")
|
||
|
procReleaseContext = modwinscard.NewProc("SCardReleaseContext")
|
||
|
procIsValidContext = modwinscard.NewProc("SCardIsValidContext")
|
||
|
procCancel = modwinscard.NewProc("SCardCancel")
|
||
|
procListReaders = modwinscard.NewProc("SCardListReadersW")
|
||
|
procListReaderGroups = modwinscard.NewProc("SCardListReaderGroupsW")
|
||
|
procGetStatusChange = modwinscard.NewProc("SCardGetStatusChangeW")
|
||
|
procConnect = modwinscard.NewProc("SCardConnectW")
|
||
|
procDisconnect = modwinscard.NewProc("SCardDisconnect")
|
||
|
procReconnect = modwinscard.NewProc("SCardReconnect")
|
||
|
procBeginTransaction = modwinscard.NewProc("SCardBeginTransaction")
|
||
|
procEndTransaction = modwinscard.NewProc("SCardEndTransaction")
|
||
|
procStatus = modwinscard.NewProc("SCardStatusW")
|
||
|
procTransmit = modwinscard.NewProc("SCardTransmit")
|
||
|
procControl = modwinscard.NewProc("SCardControl")
|
||
|
procGetAttrib = modwinscard.NewProc("SCardGetAttrib")
|
||
|
procSetAttrib = modwinscard.NewProc("SCardSetAttrib")
|
||
|
|
||
|
dataT0Pci = modwinscard.NewProc("g_rgSCardT0Pci")
|
||
|
dataT1Pci = modwinscard.NewProc("g_rgSCardT1Pci")
|
||
|
)
|
||
|
|
||
|
var scardIoReqT0 uintptr
|
||
|
var scardIoReqT1 uintptr
|
||
|
|
||
|
func init() {
|
||
|
if err := dataT0Pci.Find(); err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
scardIoReqT0 = dataT0Pci.Addr()
|
||
|
if err := dataT1Pci.Find(); err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
scardIoReqT1 = dataT1Pci.Addr()
|
||
|
}
|
||
|
|
||
|
func (e Error) Error() string {
|
||
|
err := syscall.Errno(e)
|
||
|
return fmt.Sprintf("scard: error(%x): %s", uintptr(e), err.Error())
|
||
|
}
|
||
|
|
||
|
func scardEstablishContext(scope Scope, reserved1, reserved2 uintptr) (uintptr, Error) {
|
||
|
var ctx uintptr
|
||
|
r, _, _ := procEstablishContext.Call(uintptr(scope), reserved1, reserved2, uintptr(unsafe.Pointer(&ctx)))
|
||
|
return ctx, Error(r)
|
||
|
}
|
||
|
|
||
|
func scardIsValidContext(ctx uintptr) Error {
|
||
|
r, _, _ := procIsValidContext.Call(ctx)
|
||
|
return Error(r)
|
||
|
}
|
||
|
|
||
|
func scardCancel(ctx uintptr) Error {
|
||
|
r, _, _ := procCancel.Call(ctx)
|
||
|
return Error(r)
|
||
|
}
|
||
|
|
||
|
func scardReleaseContext(ctx uintptr) Error {
|
||
|
r, _, _ := procReleaseContext.Call(ctx)
|
||
|
return Error(r)
|
||
|
}
|
||
|
|
||
|
func scardListReaders(ctx uintptr, groups, buf unsafe.Pointer, bufLen uint32) (uint32, Error) {
|
||
|
dwBufLen := uint32(bufLen)
|
||
|
r, _, _ := procListReaders.Call(ctx, uintptr(groups), uintptr(buf), uintptr(unsafe.Pointer(&dwBufLen)))
|
||
|
return dwBufLen, Error(r)
|
||
|
}
|
||
|
|
||
|
func scardListReaderGroups(ctx uintptr, buf unsafe.Pointer, bufLen uint32) (uint32, Error) {
|
||
|
dwBufLen := uint32(bufLen)
|
||
|
r, _, _ := procListReaderGroups.Call(ctx, uintptr(buf), uintptr(unsafe.Pointer(&dwBufLen)))
|
||
|
return dwBufLen, Error(r)
|
||
|
}
|
||
|
|
||
|
func scardGetStatusChange(ctx uintptr, timeout uint32, states []scardReaderState) Error {
|
||
|
r, _, _ := procGetStatusChange.Call(ctx, uintptr(timeout), uintptr(unsafe.Pointer(&states[0])), uintptr(len(states)))
|
||
|
return Error(r)
|
||
|
}
|
||
|
|
||
|
func scardConnect(ctx uintptr, reader unsafe.Pointer, shareMode ShareMode, proto Protocol) (uintptr, Protocol, Error) {
|
||
|
var handle uintptr
|
||
|
var activeProto uint32
|
||
|
|
||
|
r, _, _ := procConnect.Call(ctx, uintptr(reader), uintptr(shareMode), uintptr(proto), uintptr(unsafe.Pointer(&handle)), uintptr(unsafe.Pointer(&activeProto)))
|
||
|
|
||
|
return handle, Protocol(activeProto), Error(r)
|
||
|
}
|
||
|
|
||
|
func scardDisconnect(card uintptr, d Disposition) Error {
|
||
|
r, _, _ := procDisconnect.Call(card, uintptr(d))
|
||
|
return Error(r)
|
||
|
}
|
||
|
|
||
|
func scardReconnect(card uintptr, mode ShareMode, proto Protocol, disp Disposition) (Protocol, Error) {
|
||
|
var activeProtocol uint32
|
||
|
r, _, _ := procReconnect.Call(card, uintptr(mode), uintptr(proto), uintptr(disp), uintptr(unsafe.Pointer(&activeProtocol)))
|
||
|
return Protocol(activeProtocol), Error(r)
|
||
|
}
|
||
|
|
||
|
func scardBeginTransaction(card uintptr) Error {
|
||
|
r, _, _ := procBeginTransaction.Call(card)
|
||
|
return Error(r)
|
||
|
}
|
||
|
|
||
|
func scardEndTransaction(card uintptr, disp Disposition) Error {
|
||
|
r, _, _ := procEndTransaction.Call(card, uintptr(disp))
|
||
|
return Error(r)
|
||
|
}
|
||
|
|
||
|
func scardCardStatus(card uintptr, readerBuf strbuf, atrBuf []byte) (uint32, State, Protocol, uint32, Error) {
|
||
|
var state, proto uint32
|
||
|
var atrLen = uint32(len(atrBuf))
|
||
|
|
||
|
readerLen := uint32(len(readerBuf))
|
||
|
|
||
|
r, _, _ := procStatus.Call(card, uintptr(readerBuf.ptr()), uintptr(unsafe.Pointer(&readerLen)), uintptr(unsafe.Pointer(&state)), uintptr(unsafe.Pointer(&proto)), uintptr(unsafe.Pointer(&atrBuf[0])), uintptr(unsafe.Pointer(&atrLen)))
|
||
|
|
||
|
return readerLen, State(state), Protocol(proto), atrLen, Error(r)
|
||
|
}
|
||
|
|
||
|
func scardTransmit(card uintptr, proto Protocol, cmd []byte, rsp []byte) (uint32, Error) {
|
||
|
var sendpci uintptr
|
||
|
var rspLen = uint32(len(rsp))
|
||
|
|
||
|
switch proto {
|
||
|
case ProtocolT0:
|
||
|
sendpci = scardIoReqT0
|
||
|
case ProtocolT1:
|
||
|
sendpci = scardIoReqT1
|
||
|
default:
|
||
|
panic("unknown protocol")
|
||
|
}
|
||
|
|
||
|
r, _, _ := procTransmit.Call(card, sendpci, uintptr(unsafe.Pointer(&cmd[0])), uintptr(len(cmd)), uintptr(0), uintptr(unsafe.Pointer(&rsp[0])), uintptr(unsafe.Pointer(&rspLen)))
|
||
|
|
||
|
return rspLen, Error(r)
|
||
|
}
|
||
|
|
||
|
func scardControl(card uintptr, ioctl uint32, in, out []byte) (uint32, Error) {
|
||
|
var ptrIn uintptr
|
||
|
var outLen = uint32(len(out))
|
||
|
|
||
|
if len(in) != 0 {
|
||
|
ptrIn = uintptr(unsafe.Pointer(&in[0]))
|
||
|
}
|
||
|
|
||
|
r, _, _ := procControl.Call(card, uintptr(ioctl), ptrIn, uintptr(len(in)), uintptr(unsafe.Pointer(&out[0])), uintptr(len(out)), uintptr(unsafe.Pointer(&outLen)))
|
||
|
return outLen, Error(r)
|
||
|
}
|
||
|
|
||
|
func scardGetAttrib(card uintptr, id Attrib, buf []byte) (uint32, Error) {
|
||
|
var ptr uintptr
|
||
|
|
||
|
if len(buf) != 0 {
|
||
|
ptr = uintptr(unsafe.Pointer(&buf[0]))
|
||
|
}
|
||
|
|
||
|
bufLen := uint32(len(buf))
|
||
|
r, _, _ := procGetAttrib.Call(card, uintptr(id), ptr, uintptr(unsafe.Pointer(&bufLen)))
|
||
|
|
||
|
return bufLen, Error(r)
|
||
|
}
|
||
|
|
||
|
func scardSetAttrib(card uintptr, id Attrib, buf []byte) Error {
|
||
|
r, _, _ := procSetAttrib.Call(card, uintptr(id), uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)))
|
||
|
return Error(r)
|
||
|
}
|
||
|
|
||
|
type scardReaderState struct {
|
||
|
szReader uintptr
|
||
|
pvUserData uintptr
|
||
|
dwCurrentState uint32
|
||
|
dwEventState uint32
|
||
|
cbAtr uint32
|
||
|
rgbAtr [36]byte
|
||
|
}
|
||
|
|
||
|
func (rs *ReaderState) toSys() (scardReaderState, error) {
|
||
|
var sys scardReaderState
|
||
|
creader, err := encodestr(rs.Reader)
|
||
|
if err != nil {
|
||
|
return scardReaderState{}, err
|
||
|
}
|
||
|
sys.szReader = uintptr(creader.ptr())
|
||
|
sys.dwCurrentState = uint32(rs.CurrentState)
|
||
|
sys.cbAtr = uint32(len(rs.Atr))
|
||
|
copy(sys.rgbAtr[:], rs.Atr)
|
||
|
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))
|
||
|
copy(rs.Atr, sys.rgbAtr[:])
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type strbuf []uint16
|
||
|
|
||
|
func encodestr(s string) (strbuf, error) {
|
||
|
utf16, err := syscall.UTF16FromString(s)
|
||
|
return strbuf(utf16), err
|
||
|
}
|
||
|
|
||
|
func decodestr(buf strbuf) string {
|
||
|
return syscall.UTF16ToString(buf)
|
||
|
}
|