pcsc-lite 1.9.9
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)
96 strncpy(socketName, socketNameEnv, sizeof(socketName));
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
121INTERNAL int ClientSetupSession(uint32_t *pdwClientID)
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",
144 socketName, strerror(errno));
145 (void)close(*pdwClientID);
146 return -1;
147 }
148
149 ret = fcntl(*pdwClientID, F_GETFL, 0);
150 if (ret < 0)
151 {
152 Log3(PCSC_LOG_CRITICAL, "Error: cannot retrieve socket %s flags: %s",
153 socketName, strerror(errno));
154 (void)close(*pdwClientID);
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",
161 socketName, strerror(errno));
162 (void)close(*pdwClientID);
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
211 gettimeofday(&start, NULL);
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
221 gettimeofday(&now, NULL);
222 delta = time_sub(&now, &start) / 1000;
223
224 if (delta > timeOut)
225 {
226 /* we already timed out */
227 retval = SCARD_E_TIMEOUT;
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 readed;
244
245 if (!(read_fd.revents & POLLIN))
246 {
247 /* very strange situation. it should be an assert really */
248 retval = SCARD_F_COMM_ERROR;
249 break;
250 }
251 readed = read(filedes, buffer, remaining);
252
253 if (readed > 0)
254 {
255 /* we got something */
256 buffer += readed;
257 remaining -= readed;
258 } else if (readed == 0)
259 {
260 /* peer closed the socket */
261 retval = SCARD_F_COMM_ERROR;
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 {
269 retval = SCARD_F_COMM_ERROR;
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));
297 retval = SCARD_F_COMM_ERROR;
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 */
327 header.command = command;
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
357INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size,
358 int32_t filedes)
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 */
388 retval = SCARD_F_COMM_ERROR;
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 */
396 written = send(filedes, buffer, remaining, MSG_NOSIGNAL);
397#else
398 /* we may get a SIGPIPE signal if the other side has closed */
399 written = write(filedes, buffer, remaining);
400#endif
401
402 if (written > 0)
403 {
404 /* we wrote something */
405 buffer += written;
406 remaining -= written;
407 } else if (written == 0)
408 {
409 /* peer closed the socket */
410 retval = SCARD_F_COMM_ERROR;
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 {
418 retval = SCARD_E_NO_SERVICE;
419 break;
420 }
421 }
422 } else if (pollret == 0)
423 {
424 /* timeout */
425 retval = SCARD_E_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));
434 retval = SCARD_F_COMM_ERROR;
435 break;
436 }
437 }
438 }
439
440 return retval;
441}
442
457INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size,
458 int32_t filedes)
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 readed;
484
485 if (!(read_fd.revents & POLLIN))
486 {
487 /* very strange situation. it should be an assert really */
488 retval = SCARD_F_COMM_ERROR;
489 break;
490 }
491 readed = read(filedes, buffer, remaining);
492
493 if (readed > 0)
494 {
495 /* we got something */
496 buffer += readed;
497 remaining -= readed;
498 } else if (readed == 0)
499 {
500 /* peer closed the socket */
501 retval = SCARD_F_COMM_ERROR;
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
513 retval = SCARD_F_COMM_ERROR;
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));
525 retval = SCARD_F_COMM_ERROR;
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.
header structure for client/server message data exchange.
Definition: winscard_msg.h:68
uint32_t size
size of the message excluding this header
Definition: winscard_msg.h:69
uint32_t command
one of the pcsc_msg_commands
Definition: winscard_msg.h:70
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.
Definition: winscard_msg.c:121
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 reponse from the server or vice-versa.
Definition: winscard_msg.c:197
INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID, uint64_t size, void *data_void)
Wrapper for the MessageSend() function.
Definition: winscard_msg.c:320
INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Sends a menssage from client to server or vice-versa.
Definition: winscard_msg.c:357
INTERNAL void ClientCloseSession(uint32_t dwClientID)
Closes the socket used by the client to communicate with the server.
Definition: winscard_msg.c:175
INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Called by the Client to get the reponse from the server or vice-versa.
Definition: winscard_msg.c:457
This defines some structures and #defines to be used over the transport layer.