pcsc-lite 2.5.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-2024
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
43
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
60#include "misc.h"
61#include "pcscd.h"
62#include "winscard.h"
63#include "debuglog.h"
64#include "winscard_msg.h"
65#include "sys_generic.h"
66#include "utils.h"
67
68//#define DEBUG_PROTOCOL
69
70#ifdef PCSCD
71
72/* functions used by pcscd only */
73
74#else
75
76/* functions used by libpcsclite only */
77
78#ifndef SOCK_CLOEXEC
79#define SOCK_CLOEXEC 0
80#endif
81
82#define member_size(type, member) sizeof(((type *)0)->member)
83
84static char SocketName[member_size(struct sockaddr_un, sun_path)];
85static pthread_once_t SocketName_init_control = PTHREAD_ONCE_INIT;
86static void SocketName_init(void)
87{
88 /* socket name not yet initialized */
89 const char *socketNameEnv;
90
91 socketNameEnv = SYS_GetEnv("PCSCLITE_CSOCK_NAME");
92 if (socketNameEnv)
93 strncpy(SocketName, socketNameEnv, sizeof SocketName);
94 else
95 strncpy(SocketName, PCSCLITE_CSOCK_NAME, sizeof SocketName);
96
97 /* Ensure a NUL byte */
98 SocketName[sizeof SocketName -1] = '\0';
99}
100
101char *getSocketName(void)
102{
103 pthread_once(&SocketName_init_control, SocketName_init);
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 ssize_t bytes_read;
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 bytes_read = read(filedes, buffer, remaining);
252
253 if (bytes_read > 0)
254 {
255 /* we got something */
256 buffer += bytes_read;
257 remaining -= bytes_read;
258 } else if (bytes_read == 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? */
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 unsigned 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#ifdef DEBUG_PROTOCOL
369 Log2(PCSC_LOG_DEBUG, "write %ld bytes", buffer_size);
370 LogXxd(PCSC_LOG_DEBUG, "write: ", buffer, buffer_size);
371#endif
372 /* repeat until all data is written */
373 while (remaining > 0)
374 {
375 struct pollfd write_fd;
376 int pollret;
377
378 write_fd.fd = filedes;
379 write_fd.events = POLLOUT;
380 write_fd.revents = 0;
381
382 pollret = poll(&write_fd, 1, -1);
383
384 /* try to write only when the file descriptor is writable */
385 if (pollret > 0)
386 {
387 ssize_t written;
388
389 if (!(write_fd.revents & POLLOUT))
390 {
391 /* very strange situation. it should be an assert really */
392 retval = SCARD_F_COMM_ERROR;
393 break;
394 }
395 /* since we are a user library we can't play with signals
396 * The signals may already be used by the application */
397#ifdef MSG_NOSIGNAL
398 /* Get EPIPE return code instead of SIGPIPE signal
399 * Works on Linux */
400 written = send(filedes, buffer, remaining, MSG_NOSIGNAL);
401#else
402 /* we may get a SIGPIPE signal if the other side has closed */
403 written = write(filedes, buffer, remaining);
404#endif
405
406 if (written > 0)
407 {
408 /* we wrote something */
409 buffer += written;
410 remaining -= written;
411 } else if (written == 0)
412 {
413 /* peer closed the socket */
414 retval = SCARD_F_COMM_ERROR;
415 break;
416 } else
417 {
418 /* we ignore the signals and socket full situations, all
419 * other errors are fatal */
420 if (errno != EINTR && errno != EAGAIN)
421 {
422 retval = SCARD_E_NO_SERVICE;
423 break;
424 }
425 }
426 } else if (pollret == 0)
427 {
428 /* timeout */
429 retval = SCARD_E_TIMEOUT;
430 break;
431 } else
432 {
433 /* ignore signals */
434 if (errno != EINTR)
435 {
436 Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
437 strerror(errno));
438 retval = SCARD_F_COMM_ERROR;
439 break;
440 }
441 }
442 }
443
444 return retval;
445}
446
461INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size,
462 int32_t filedes)
463{
464 char *buffer = buffer_void;
465
466 /* default is success */
467 LONG retval = SCARD_S_SUCCESS;
468
469 /* how many bytes we must read */
470 size_t remaining = buffer_size;
471
472#ifdef DEBUG_PROTOCOL
473 Log2(PCSC_LOG_DEBUG, "read %ld bytes", buffer_size);
474#endif
475 /* repeat until we get the whole message */
476 while (remaining > 0)
477 {
478 struct pollfd read_fd;
479 int pollret;
480
481 read_fd.fd = filedes;
482 read_fd.events = POLLIN;
483 read_fd.revents = 0;
484
485 pollret = poll(&read_fd, 1 , -1);
486
487 /* try to read only when socket is readable */
488 if (pollret > 0)
489 {
490 ssize_t bytes_read;
491
492 if (!(read_fd.revents & POLLIN))
493 {
494 /* very strange situation. it should be an assert really */
495 retval = SCARD_F_COMM_ERROR;
496 break;
497 }
498 bytes_read = read(filedes, buffer, remaining);
499
500 if (bytes_read > 0)
501 {
502 /* we got something */
503 buffer += bytes_read;
504 remaining -= bytes_read;
505 } else if (bytes_read == 0)
506 {
507 /* peer closed the socket */
508 retval = SCARD_F_COMM_ERROR;
509 break;
510 } else
511 {
512 /* we ignore the signals and empty socket situations, all
513 * other errors are fatal */
514 if (errno != EINTR && errno != EAGAIN)
515 {
516 /* connection reset by pcscd? */
517 if (ECONNRESET == errno)
519 else
520 retval = SCARD_F_COMM_ERROR;
521 break;
522 }
523 }
524 }
525 else
526 {
527 /* we ignore signals, all other errors are fatal */
528 if (errno != EINTR)
529 {
530 Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
531 strerror(errno));
532 retval = SCARD_F_COMM_ERROR;
533 break;
534 }
535 }
536 }
537
538#ifdef DEBUG_PROTOCOL
539 LogXxd(PCSC_LOG_DEBUG, "read: ", buffer_void, buffer_size);
540#endif
541
542 return retval;
543}
544
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
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.
const char * SYS_GetEnv(const char *name)
(More) secure version of getenv(3)
Definition sys_unix.c:168
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.
LONG SCardCheckDaemonAvailability(void)
Checks if the server is running.
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.