pcsc-lite 2.0.1
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
122INTERNAL int ClientSetupSession(uint32_t *pdwClientID)
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",
145 socketName, strerror(errno));
146 (void)close(*pdwClientID);
147 return -1;
148 }
149
150 ret = fcntl(*pdwClientID, F_GETFL, 0);
151 if (ret < 0)
152 {
153 Log3(PCSC_LOG_CRITICAL, "Error: cannot retrieve socket %s flags: %s",
154 socketName, strerror(errno));
155 (void)close(*pdwClientID);
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",
162 socketName, strerror(errno));
163 (void)close(*pdwClientID);
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
212 gettimeofday(&start, NULL);
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
222 gettimeofday(&now, NULL);
223 delta = time_sub(&now, &start) / 1000;
224
225 if (delta > timeOut)
226 {
227 /* we already timed out */
228 retval = SCARD_E_TIMEOUT;
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 */
249 retval = SCARD_F_COMM_ERROR;
250 break;
251 }
252 bytes_read = read(filedes, buffer, remaining);
253
254 if (bytes_read > 0)
255 {
256 /* we got something */
257 buffer += bytes_read;
258 remaining -= bytes_read;
259 } else if (bytes_read == 0)
260 {
261 /* peer closed the socket */
262 retval = SCARD_F_COMM_ERROR;
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 {
270 retval = SCARD_F_COMM_ERROR;
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));
298 retval = SCARD_F_COMM_ERROR;
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 */
328 header.command = command;
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
358INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size,
359 int32_t filedes)
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 */
389 retval = SCARD_F_COMM_ERROR;
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 */
397 written = send(filedes, buffer, remaining, MSG_NOSIGNAL);
398#else
399 /* we may get a SIGPIPE signal if the other side has closed */
400 written = write(filedes, buffer, remaining);
401#endif
402
403 if (written > 0)
404 {
405 /* we wrote something */
406 buffer += written;
407 remaining -= written;
408 } else if (written == 0)
409 {
410 /* peer closed the socket */
411 retval = SCARD_F_COMM_ERROR;
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 {
419 retval = SCARD_E_NO_SERVICE;
420 break;
421 }
422 }
423 } else if (pollret == 0)
424 {
425 /* timeout */
426 retval = SCARD_E_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));
435 retval = SCARD_F_COMM_ERROR;
436 break;
437 }
438 }
439 }
440
441 return retval;
442}
443
458INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size,
459 int32_t filedes)
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 */
489 retval = SCARD_F_COMM_ERROR;
490 break;
491 }
492 bytes_read = read(filedes, buffer, remaining);
493
494 if (bytes_read > 0)
495 {
496 /* we got something */
497 buffer += bytes_read;
498 remaining -= bytes_read;
499 } else if (bytes_read == 0)
500 {
501 /* peer closed the socket */
502 retval = SCARD_F_COMM_ERROR;
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 reseted by pcscd? */
511 if (ECONNRESET == errno)
513 else
514 retval = SCARD_F_COMM_ERROR;
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));
526 retval = SCARD_F_COMM_ERROR;
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: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.
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.