pcsc-lite 2.0.3
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
85static char SocketName[member_size(struct sockaddr_un, sun_path)];
86static pthread_once_t SocketName_init_control = PTHREAD_ONCE_INIT;
87static void SocketName_init(void)
88{
89 /* socket name not yet initialized */
90 char *socketNameEnv;
91
92 socketNameEnv = getenv("PCSCLITE_CSOCK_NAME");
93 if (socketNameEnv)
94 strncpy(SocketName, socketNameEnv, sizeof SocketName);
95 else
96 strncpy(SocketName, PCSCLITE_CSOCK_NAME, sizeof SocketName);
97
98 /* Ensure a NUL byte */
99 SocketName[sizeof SocketName -1] = '\0';
100}
101
102char *getSocketName(void)
103{
104 pthread_once(&SocketName_init_control, SocketName_init);
105 return SocketName;
106}
107
123{
124 struct sockaddr_un svc_addr;
125 int ret;
126 char *socketName;
127
128 ret = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
129 if (ret < 0)
130 {
131 Log2(PCSC_LOG_CRITICAL, "Error: create on client socket: %s",
132 strerror(errno));
133 return -1;
134 }
135 *pdwClientID = ret;
136
137 socketName = getSocketName();
138 svc_addr.sun_family = AF_UNIX;
139 strncpy(svc_addr.sun_path, socketName, sizeof(svc_addr.sun_path));
140
141 if (connect(*pdwClientID, (struct sockaddr *) &svc_addr,
142 sizeof(svc_addr.sun_family) + strlen(svc_addr.sun_path) + 1) < 0)
143 {
144 Log3(PCSC_LOG_CRITICAL, "Error: connect to client socket %s: %s",
147 return -1;
148 }
149
151 if (ret < 0)
152 {
153 Log3(PCSC_LOG_CRITICAL, "Error: cannot retrieve socket %s flags: %s",
156 return -1;
157 }
158
159 if (fcntl(*pdwClientID, F_SETFL, ret | O_NONBLOCK) < 0)
160 {
161 Log3(PCSC_LOG_CRITICAL, "Error: cannot set socket %s nonblocking: %s",
164 return -1;
165 }
166
167 return 0;
168}
169
176INTERNAL void ClientCloseSession(uint32_t dwClientID)
177{
178 close(dwClientID);
179}
180
198INTERNAL LONG MessageReceiveTimeout(uint32_t command, void *buffer_void,
199 uint64_t buffer_size, int32_t filedes, long timeOut)
200{
201 char *buffer = buffer_void;
202
203 /* default is success */
204 LONG retval = SCARD_S_SUCCESS;
205
206 /* record the time when we started */
207 struct timeval start;
208
209 /* how many bytes we must read */
210 size_t remaining = buffer_size;
211
213
214 /* repeat until we get the whole message */
215 while (remaining > 0)
216 {
217 struct pollfd read_fd;
218 struct timeval now;
219 int pollret;
220 long delta;
221
223 delta = time_sub(&now, &start) / 1000;
224
225 if (delta > timeOut)
226 {
227 /* we already timed out */
229 break;
230 }
231
232 /* remaining time to wait */
233 delta = timeOut - delta;
234
235 read_fd.fd = filedes;
236 read_fd.events = POLLIN;
237 read_fd.revents = 0;
238
239 pollret = poll(&read_fd, 1, delta);
240
241 /* try to read only when socket is readable */
242 if (pollret > 0)
243 {
244 int bytes_read;
245
246 if (!(read_fd.revents & POLLIN))
247 {
248 /* very strange situation. it should be an assert really */
250 break;
251 }
253
254 if (bytes_read > 0)
255 {
256 /* we got something */
259 } else if (bytes_read == 0)
260 {
261 /* peer closed the socket */
263 break;
264 } else
265 {
266 /* we ignore the signals and empty socket situations, all
267 * other errors are fatal */
268 if (errno != EINTR && errno != EAGAIN)
269 {
271 break;
272 }
273 }
274 } else if (pollret == 0)
275 {
276 /* is the daemon still there? */
277 retval = SCardCheckDaemonAvailability();
278 if (retval != SCARD_S_SUCCESS)
279 {
280 /* timeout */
281 break;
282 }
283
284 /* you need to set the env variable PCSCLITE_DEBUG=0 since
285 * this is logged on the client side and not on the pcscd
286 * side*/
287#ifdef NO_LOG
288 (void)command;
289#endif
290 Log2(PCSC_LOG_INFO, "Command 0x%X not yet finished", command);
291 } else
292 {
293 /* we ignore signals, all other errors are fatal */
294 if (errno != EINTR)
295 {
296 Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
297 strerror(errno));
299 break;
300 }
301 }
302 }
303
304 return retval;
305}
306
321INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID,
322 uint64_t size, void *data_void)
323{
324 struct rxHeader header;
325 LONG ret;
326
327 /* header */
329 header.size = size;
330 ret = MessageSend(&header, sizeof(header), dwClientID);
331
332 /* command */
333 if (size > 0)
334 ret = MessageSend(data_void, size, dwClientID);
335
336 return ret;
337}
338
339#endif
340
341/* functions used by pcscd and libpcsclite */
342
360{
361 char *buffer = buffer_void;
362
363 /* default is success */
364 LONG retval = SCARD_S_SUCCESS;
365
366 /* how many bytes remains to be written */
367 size_t remaining = buffer_size;
368
369 /* repeat until all data is written */
370 while (remaining > 0)
371 {
372 struct pollfd write_fd;
373 int pollret;
374
375 write_fd.fd = filedes;
376 write_fd.events = POLLOUT;
377 write_fd.revents = 0;
378
379 pollret = poll(&write_fd, 1, -1);
380
381 /* try to write only when the file descriptor is writable */
382 if (pollret > 0)
383 {
384 int written;
385
386 if (!(write_fd.revents & POLLOUT))
387 {
388 /* very strange situation. it should be an assert really */
390 break;
391 }
392 /* since we are a user library we can't play with signals
393 * The signals may already be used by the application */
394#ifdef MSG_NOSIGNAL
395 /* Get EPIPE return code instead of SIGPIPE signal
396 * Works on Linux */
398#else
399 /* we may get a SIGPIPE signal if the other side has closed */
401#endif
402
403 if (written > 0)
404 {
405 /* we wrote something */
406 buffer += written;
408 } else if (written == 0)
409 {
410 /* peer closed the socket */
412 break;
413 } else
414 {
415 /* we ignore the signals and socket full situations, all
416 * other errors are fatal */
417 if (errno != EINTR && errno != EAGAIN)
418 {
420 break;
421 }
422 }
423 } else if (pollret == 0)
424 {
425 /* timeout */
427 break;
428 } else
429 {
430 /* ignore signals */
431 if (errno != EINTR)
432 {
433 Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
434 strerror(errno));
436 break;
437 }
438 }
439 }
440
441 return retval;
442}
443
460{
461 char *buffer = buffer_void;
462
463 /* default is success */
464 LONG retval = SCARD_S_SUCCESS;
465
466 /* how many bytes we must read */
467 size_t remaining = buffer_size;
468
469 /* repeat until we get the whole message */
470 while (remaining > 0)
471 {
472 struct pollfd read_fd;
473 int pollret;
474
475 read_fd.fd = filedes;
476 read_fd.events = POLLIN;
477 read_fd.revents = 0;
478
479 pollret = poll(&read_fd, 1 , -1);
480
481 /* try to read only when socket is readable */
482 if (pollret > 0)
483 {
484 int bytes_read;
485
486 if (!(read_fd.revents & POLLIN))
487 {
488 /* very strange situation. it should be an assert really */
490 break;
491 }
493
494 if (bytes_read > 0)
495 {
496 /* we got something */
499 } else if (bytes_read == 0)
500 {
501 /* peer closed the socket */
503 break;
504 } else
505 {
506 /* we ignore the signals and empty socket situations, all
507 * other errors are fatal */
508 if (errno != EINTR && errno != EAGAIN)
509 {
510 /* connection reset by pcscd? */
511 if (ECONNRESET == errno)
513 else
515 break;
516 }
517 }
518 }
519 else
520 {
521 /* we ignore signals, all other errors are fatal */
522 if (errno != EINTR)
523 {
524 Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
525 strerror(errno));
527 break;
528 }
529 }
530 }
531
532 return retval;
533}
534
This handles debugging.
#define SCARD_W_SECURITY_VIOLATION
Access was denied because of a security violation.
Definition pcsclite.h:222
#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.