pcsc-lite 2.0.0
winscard_msg.c
Go to the documentation of this file.
1/*
2 * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3 *
4 * Copyright (C) 2001-2004
5 * David Corcoran <corcoran@musclecard.com>
6 * Copyright (C) 2003-2004
7 * Damien Sauveron <damien.sauveron@labri.fr>
8 * Copyright (C) 2002-2010
9 * Ludovic Rousseau <ludovic.rousseau@free.fr>
10 *
11Redistribution and use in source and binary forms, with or without
12modification, are permitted provided that the following conditions
13are met:
14
151. Redistributions of source code must retain the above copyright
16 notice, this list of conditions and the following disclaimer.
172. Redistributions in binary form must reproduce the above copyright
18 notice, this list of conditions and the following disclaimer in the
19 documentation and/or other materials provided with the distribution.
203. The name of the author may not be used to endorse or promote products
21 derived from this software without specific prior written permission.
22
23THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
44#include "config.h"
45#include <fcntl.h>
46#include <unistd.h>
47#include <sys/types.h>
48#include <sys/stat.h>
49#include <sys/socket.h>
50#include <sys/time.h>
51#include <sys/un.h>
52#include <sys/ioctl.h>
53#include <errno.h>
54#include <poll.h>
55#include <stdio.h>
56#include <time.h>
57#include <string.h>
58#include <stdlib.h>
59#ifdef HAVE_SYS_FILIO_H
60#include <sys/filio.h>
61#endif
62
63#include "misc.h"
64#include "pcscd.h"
65#include "winscard.h"
66#include "debuglog.h"
67#include "winscard_msg.h"
68#include "sys_generic.h"
69#include "utils.h"
70
71#ifdef PCSCD
72
73/* functions used by pcscd only */
74
75#else
76
77/* functions used by libpcsclite only */
78
79#ifndef SOCK_CLOEXEC
80#define SOCK_CLOEXEC 0
81#endif
82
83#define member_size(type, member) sizeof(((type *)0)->member)
84
85char *getSocketName(void)
86{
87 static char socketName[member_size(struct sockaddr_un, sun_path)];
88
89 if ('\0' == socketName[0])
90 {
91 /* socket name not yet initialized */
92 char *socketNameEnv;
93
94 socketNameEnv = getenv("PCSCLITE_CSOCK_NAME");
95 if (socketNameEnv)
97 else
98 strncpy(socketName, PCSCLITE_CSOCK_NAME, sizeof(socketName));
99
100 /* Ensure a NUL byte */
101 socketName[sizeof socketName -1] = '\0';
102 }
103
104 return socketName;
105}
106
122{
123 struct sockaddr_un svc_addr;
124 int ret;
125 char *socketName;
126
127 ret = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
128 if (ret < 0)
129 {
130 Log2(PCSC_LOG_CRITICAL, "Error: create on client socket: %s",
131 strerror(errno));
132 return -1;
133 }
134 *pdwClientID = ret;
135
136 socketName = getSocketName();
137 svc_addr.sun_family = AF_UNIX;
138 strncpy(svc_addr.sun_path, socketName, sizeof(svc_addr.sun_path));
139
140 if (connect(*pdwClientID, (struct sockaddr *) &svc_addr,
141 sizeof(svc_addr.sun_family) + strlen(svc_addr.sun_path) + 1) < 0)
142 {
143 Log3(PCSC_LOG_CRITICAL, "Error: connect to client socket %s: %s",
146 return -1;
147 }
148
150 if (ret < 0)
151 {
152 Log3(PCSC_LOG_CRITICAL, "Error: cannot retrieve socket %s flags: %s",
155 return -1;
156 }
157
158 if (fcntl(*pdwClientID, F_SETFL, ret | O_NONBLOCK) < 0)
159 {
160 Log3(PCSC_LOG_CRITICAL, "Error: cannot set socket %s nonblocking: %s",
163 return -1;
164 }
165
166 return 0;
167}
168
175INTERNAL void ClientCloseSession(uint32_t dwClientID)
176{
177 close(dwClientID);
178}
179
197INTERNAL LONG MessageReceiveTimeout(uint32_t command, void *buffer_void,
198 uint64_t buffer_size, int32_t filedes, long timeOut)
199{
200 char *buffer = buffer_void;
201
202 /* default is success */
203 LONG retval = SCARD_S_SUCCESS;
204
205 /* record the time when we started */
206 struct timeval start;
207
208 /* how many bytes we must read */
209 size_t remaining = buffer_size;
210
212
213 /* repeat until we get the whole message */
214 while (remaining > 0)
215 {
216 struct pollfd read_fd;
217 struct timeval now;
218 int pollret;
219 long delta;
220
222 delta = time_sub(&now, &start) / 1000;
223
224 if (delta > timeOut)
225 {
226 /* we already timed out */
228 break;
229 }
230
231 /* remaining time to wait */
232 delta = timeOut - delta;
233
234 read_fd.fd = filedes;
235 read_fd.events = POLLIN;
236 read_fd.revents = 0;
237
238 pollret = poll(&read_fd, 1, delta);
239
240 /* try to read only when socket is readable */
241 if (pollret > 0)
242 {
243 int bytes_read;
244
245 if (!(read_fd.revents & POLLIN))
246 {
247 /* very strange situation. it should be an assert really */
249 break;
250 }
252
253 if (bytes_read > 0)
254 {
255 /* we got something */
258 } else if (bytes_read == 0)
259 {
260 /* peer closed the socket */
262 break;
263 } else
264 {
265 /* we ignore the signals and empty socket situations, all
266 * other errors are fatal */
267 if (errno != EINTR && errno != EAGAIN)
268 {
270 break;
271 }
272 }
273 } else if (pollret == 0)
274 {
275 /* is the daemon still there? */
276 retval = SCardCheckDaemonAvailability();
277 if (retval != SCARD_S_SUCCESS)
278 {
279 /* timeout */
280 break;
281 }
282
283 /* you need to set the env variable PCSCLITE_DEBUG=0 since
284 * this is logged on the client side and not on the pcscd
285 * side*/
286#ifdef NO_LOG
287 (void)command;
288#endif
289 Log2(PCSC_LOG_INFO, "Command 0x%X not yet finished", command);
290 } else
291 {
292 /* we ignore signals, all other errors are fatal */
293 if (errno != EINTR)
294 {
295 Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
296 strerror(errno));
298 break;
299 }
300 }
301 }
302
303 return retval;
304}
305
320INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID,
321 uint64_t size, void *data_void)
322{
323 struct rxHeader header;
324 LONG ret;
325
326 /* header */
328 header.size = size;
329 ret = MessageSend(&header, sizeof(header), dwClientID);
330
331 /* command */
332 if (size > 0)
333 ret = MessageSend(data_void, size, dwClientID);
334
335 return ret;
336}
337
338#endif
339
340/* functions used by pcscd and libpcsclite */
341
359{
360 char *buffer = buffer_void;
361
362 /* default is success */
363 LONG retval = SCARD_S_SUCCESS;
364
365 /* how many bytes remains to be written */
366 size_t remaining = buffer_size;
367
368 /* repeat until all data is written */
369 while (remaining > 0)
370 {
371 struct pollfd write_fd;
372 int pollret;
373
374 write_fd.fd = filedes;
375 write_fd.events = POLLOUT;
376 write_fd.revents = 0;
377
378 pollret = poll(&write_fd, 1, -1);
379
380 /* try to write only when the file descriptor is writable */
381 if (pollret > 0)
382 {
383 int written;
384
385 if (!(write_fd.revents & POLLOUT))
386 {
387 /* very strange situation. it should be an assert really */
389 break;
390 }
391 /* since we are a user library we can't play with signals
392 * The signals may already be used by the application */
393#ifdef MSG_NOSIGNAL
394 /* Get EPIPE return code instead of SIGPIPE signal
395 * Works on Linux */
397#else
398 /* we may get a SIGPIPE signal if the other side has closed */
400#endif
401
402 if (written > 0)
403 {
404 /* we wrote something */
405 buffer += written;
407 } else if (written == 0)
408 {
409 /* peer closed the socket */
411 break;
412 } else
413 {
414 /* we ignore the signals and socket full situations, all
415 * other errors are fatal */
416 if (errno != EINTR && errno != EAGAIN)
417 {
419 break;
420 }
421 }
422 } else if (pollret == 0)
423 {
424 /* timeout */
426 break;
427 } else
428 {
429 /* ignore signals */
430 if (errno != EINTR)
431 {
432 Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
433 strerror(errno));
435 break;
436 }
437 }
438 }
439
440 return retval;
441}
442
459{
460 char *buffer = buffer_void;
461
462 /* default is success */
463 LONG retval = SCARD_S_SUCCESS;
464
465 /* how many bytes we must read */
466 size_t remaining = buffer_size;
467
468 /* repeat until we get the whole message */
469 while (remaining > 0)
470 {
471 struct pollfd read_fd;
472 int pollret;
473
474 read_fd.fd = filedes;
475 read_fd.events = POLLIN;
476 read_fd.revents = 0;
477
478 pollret = poll(&read_fd, 1 , -1);
479
480 /* try to read only when socket is readable */
481 if (pollret > 0)
482 {
483 int bytes_read;
484
485 if (!(read_fd.revents & POLLIN))
486 {
487 /* very strange situation. it should be an assert really */
489 break;
490 }
492
493 if (bytes_read > 0)
494 {
495 /* we got something */
498 } else if (bytes_read == 0)
499 {
500 /* peer closed the socket */
502 break;
503 } else
504 {
505 /* we ignore the signals and empty socket situations, all
506 * other errors are fatal */
507 if (errno != EINTR && errno != EAGAIN)
508 {
509 /* connection reseted by pcscd? */
510 if (ECONNRESET == errno)
512 else
514 break;
515 }
516 }
517 }
518 else
519 {
520 /* we ignore signals, all other errors are fatal */
521 if (errno != EINTR)
522 {
523 Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
524 strerror(errno));
526 break;
527 }
528 }
529 }
530
531 return retval;
532}
533
This handles debugging.
#define SCARD_W_SECURITY_VIOLATION
Access was denied because of a security violation.
Definition pcsclite.h:221
#define SCARD_S_SUCCESS
No error was encountered.
Definition pcsclite.h:107
#define SCARD_F_COMM_ERROR
An internal communications error has been detected.
Definition pcsclite.h:145
#define SCARD_E_TIMEOUT
The user-specified timeout value has expired.
Definition pcsclite.h:127
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
Definition pcsclite.h:165
This keeps a list of defines for pcsc-lite.
@ POWER_STATE_POWERED
powered
Definition pcscd.h:64
header structure for client/server message data exchange.
uint32_t size
size of the message excluding this header
uint32_t command
one of the pcsc_msg_commands
This handles abstract system level calls.
long int time_sub(struct timeval *a, struct timeval *b)
return the difference (as long int) in µs between 2 struct timeval r = a - b
Definition utils.c:138
This handles smart card reader communications.
INTERNAL int ClientSetupSession(uint32_t *pdwClientID)
Prepares a communication channel for the client to talk to the server.
INTERNAL LONG MessageReceiveTimeout(uint32_t command, void *buffer_void, uint64_t buffer_size, int32_t filedes, long timeOut)
Called by the Client to get the response from the server or vice-versa.
INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID, uint64_t size, void *data_void)
Wrapper for the MessageSend() function.
INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Sends a menssage from client to server or vice-versa.
INTERNAL void ClientCloseSession(uint32_t dwClientID)
Closes the socket used by the client to communicate with the server.
INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Called by the Client to get the response from the server or vice-versa.
This defines some structures and #defines to be used over the transport layer.