pcsc-lite  1.8.14
winscard_msg.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( http://pcsclite.alioth.debian.org/pcsclite.html )
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  *
11 Redistribution and use in source and binary forms, with or without
12 modification, are permitted provided that the following conditions
13 are met:
14 
15 1. Redistributions of source code must retain the above copyright
16  notice, this list of conditions and the following disclaimer.
17 2. 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.
20 3. 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 
23 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  * $Id$
35  */
36 
46 #include "config.h"
47 #include <fcntl.h>
48 #include <unistd.h>
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 #include <sys/socket.h>
52 #include <sys/time.h>
53 #include <sys/un.h>
54 #include <sys/ioctl.h>
55 #include <errno.h>
56 #include <stdio.h>
57 #include <time.h>
58 #include <string.h>
59 #include <stdlib.h>
60 #ifdef HAVE_SYS_FILIO_H
61 #include <sys/filio.h>
62 #endif
63 
64 #include "misc.h"
65 #include "pcscd.h"
66 #include "winscard.h"
67 #include "debuglog.h"
68 #include "winscard_msg.h"
69 #include "sys_generic.h"
70 #include "utils.h"
71 
72 #ifdef PCSCD
73 
74 /* functions used by pcscd only */
75 
76 #else
77 
78 /* functions used by libpcsclite only */
79 
80 #ifndef SOCK_CLOEXEC
81 #define SOCK_CLOEXEC 0
82 #endif
83 
84 char *getSocketName(void)
85 {
86  static char socketName[sizeof(struct sockaddr_un)];
87 
88  if ('\0' == socketName[0])
89  {
90  /* socket name not yet initialized */
91  char *socketNameEnv;
92 
93  socketNameEnv = getenv("PCSCLITE_CSOCK_NAME");
94  if (socketNameEnv)
95  strncpy(socketName, socketNameEnv, sizeof(socketName));
96  else
97  strncpy(socketName, PCSCLITE_CSOCK_NAME, sizeof(socketName));
98 
99  /* Ensure a NUL byte */
100  socketName[sizeof socketName -1] = '\0';
101  }
102 
103  return socketName;
104 }
105 
119 INTERNAL int ClientSetupSession(uint32_t *pdwClientID)
120 {
121  struct sockaddr_un svc_addr;
122  int ret;
123  char *socketName;
124 
125  ret = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
126  if (ret < 0)
127  {
128  Log2(PCSC_LOG_CRITICAL, "Error: create on client socket: %s",
129  strerror(errno));
130  return -1;
131  }
132  *pdwClientID = ret;
133 
134  socketName = getSocketName();
135  svc_addr.sun_family = AF_UNIX;
136  strncpy(svc_addr.sun_path, socketName, sizeof(svc_addr.sun_path));
137 
138  if (connect(*pdwClientID, (struct sockaddr *) &svc_addr,
139  sizeof(svc_addr.sun_family) + strlen(svc_addr.sun_path) + 1) < 0)
140  {
141  Log3(PCSC_LOG_CRITICAL, "Error: connect to client socket %s: %s",
142  socketName, strerror(errno));
143  (void)close(*pdwClientID);
144  return -1;
145  }
146 
147  ret = fcntl(*pdwClientID, F_GETFL, 0);
148  if (ret < 0)
149  {
150  Log3(PCSC_LOG_CRITICAL, "Error: cannot retrieve socket %s flags: %s",
151  socketName, strerror(errno));
152  (void)close(*pdwClientID);
153  return -1;
154  }
155 
156  if (fcntl(*pdwClientID, F_SETFL, ret | O_NONBLOCK) < 0)
157  {
158  Log3(PCSC_LOG_CRITICAL, "Error: cannot set socket %s nonblocking: %s",
159  socketName, strerror(errno));
160  (void)close(*pdwClientID);
161  return -1;
162  }
163 
164  return 0;
165 }
166 
174 INTERNAL int ClientCloseSession(uint32_t dwClientID)
175 {
176  return close(dwClientID);
177 }
178 
195 INTERNAL LONG MessageReceiveTimeout(uint32_t command, void *buffer_void,
196  uint64_t buffer_size, int32_t filedes, long timeOut)
197 {
198  char *buffer = buffer_void;
199 
200  /* default is success */
201  LONG retval = SCARD_S_SUCCESS;
202 
203  /* record the time when we started */
204  struct timeval start;
205 
206  /* how many bytes we must read */
207  size_t remaining = buffer_size;
208 
209  gettimeofday(&start, NULL);
210 
211  /* repeat until we get the whole message */
212  while (remaining > 0)
213  {
214  fd_set read_fd;
215  struct timeval timeout, now;
216  int selret;
217  long delta;
218 
219  gettimeofday(&now, NULL);
220  delta = time_sub(&now, &start);
221 
222  if (delta > timeOut*1000)
223  {
224  /* we already timed out */
225  retval = SCARD_E_TIMEOUT;
226  break;
227  }
228 
229  /* remaining time to wait */
230  delta = timeOut*1000 - delta;
231 
232  FD_ZERO(&read_fd);
233  FD_SET(filedes, &read_fd);
234 
235  timeout.tv_sec = delta/1000000;
236  timeout.tv_usec = delta - timeout.tv_sec*1000000;
237 
238  selret = select(filedes + 1, &read_fd, NULL, NULL, &timeout);
239 
240  /* try to read only when socket is readable */
241  if (selret > 0)
242  {
243  int readed;
244 
245  if (!FD_ISSET(filedes, &read_fd))
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 (selret == 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  Log2(PCSC_LOG_INFO, "Command 0x%X not yet finished", command);
287  } else
288  {
289  /* we ignore signals, all other errors are fatal */
290  if (errno != EINTR)
291  {
292  Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
293  strerror(errno));
294  retval = SCARD_F_COMM_ERROR;
295  break;
296  }
297  }
298  }
299 
300  return retval;
301 }
302 
317 INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID,
318  uint64_t size, void *data_void)
319 {
320  struct rxHeader header;
321  LONG ret;
322 
323  /* header */
324  header.command = command;
325  header.size = size;
326  ret = MessageSend(&header, sizeof(header), dwClientID);
327 
328  /* command */
329  if (size > 0)
330  ret = MessageSend(data_void, size, dwClientID);
331 
332  return ret;
333 }
334 
335 #endif
336 
337 /* functions used by pcscd and libpcsclite */
338 
353 INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size,
354  int32_t filedes)
355 {
356  char *buffer = buffer_void;
357 
358  /* default is success */
359  LONG retval = SCARD_S_SUCCESS;
360 
361  /* how many bytes remains to be written */
362  size_t remaining = buffer_size;
363 
364  /* repeat until all data is written */
365  while (remaining > 0)
366  {
367  fd_set write_fd;
368  int selret;
369 
370  FD_ZERO(&write_fd);
371  FD_SET(filedes, &write_fd);
372 
373  selret = select(filedes + 1, NULL, &write_fd, NULL, NULL);
374 
375  /* try to write only when the file descriptor is writable */
376  if (selret > 0)
377  {
378  int written;
379 
380  if (!FD_ISSET(filedes, &write_fd))
381  {
382  /* very strange situation. it should be an assert really */
383  retval = SCARD_F_COMM_ERROR;
384  break;
385  }
386  /* since we are a user library we can't play with signals
387  * The signals may already be used by the application */
388 #ifdef MSG_NOSIGNAL
389  /* Get EPIPE return code instead of SIGPIPE signal
390  * Works on Linux */
391  written = send(filedes, buffer, remaining, MSG_NOSIGNAL);
392 #else
393  /* we may get a SIGPIPE signal if the other side has closed */
394  written = write(filedes, buffer, remaining);
395 #endif
396 
397  if (written > 0)
398  {
399  /* we wrote something */
400  buffer += written;
401  remaining -= written;
402  } else if (written == 0)
403  {
404  /* peer closed the socket */
405  retval = SCARD_F_COMM_ERROR;
406  break;
407  } else
408  {
409  /* we ignore the signals and socket full situations, all
410  * other errors are fatal */
411  if (errno != EINTR && errno != EAGAIN)
412  {
413  retval = SCARD_E_NO_SERVICE;
414  break;
415  }
416  }
417  } else if (selret == 0)
418  {
419  /* timeout */
420  retval = SCARD_E_TIMEOUT;
421  break;
422  } else
423  {
424  /* ignore signals */
425  if (errno != EINTR)
426  {
427  Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
428  strerror(errno));
429  retval = SCARD_F_COMM_ERROR;
430  break;
431  }
432  }
433  }
434 
435  return retval;
436 }
437 
451 INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size,
452  int32_t filedes)
453 {
454  char *buffer = buffer_void;
455 
456  /* default is success */
457  LONG retval = SCARD_S_SUCCESS;
458 
459  /* how many bytes we must read */
460  size_t remaining = buffer_size;
461 
462  /* repeat until we get the whole message */
463  while (remaining > 0)
464  {
465  fd_set read_fd;
466  int selret;
467 
468  FD_ZERO(&read_fd);
469  FD_SET(filedes, &read_fd);
470 
471  selret = select(filedes + 1, &read_fd, NULL, NULL, NULL);
472 
473  /* try to read only when socket is readable */
474  if (selret > 0)
475  {
476  int readed;
477 
478  if (!FD_ISSET(filedes, &read_fd))
479  {
480  /* very strange situation. it should be an assert really */
481  retval = SCARD_F_COMM_ERROR;
482  break;
483  }
484  readed = read(filedes, buffer, remaining);
485 
486  if (readed > 0)
487  {
488  /* we got something */
489  buffer += readed;
490  remaining -= readed;
491  } else if (readed == 0)
492  {
493  /* peer closed the socket */
494  retval = SCARD_F_COMM_ERROR;
495  break;
496  } else
497  {
498  /* we ignore the signals and empty socket situations, all
499  * other errors are fatal */
500  if (errno != EINTR && errno != EAGAIN)
501  {
502  retval = SCARD_F_COMM_ERROR;
503  break;
504  }
505  }
506  }
507  else
508  {
509  /* we ignore signals, all other errors are fatal */
510  if (errno != EINTR)
511  {
512  Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
513  strerror(errno));
514  retval = SCARD_F_COMM_ERROR;
515  break;
516  }
517  }
518  }
519 
520  return retval;
521 }
522 
INTERNAL int ClientCloseSession(uint32_t dwClientID)
Closes the socket used by the client to communicate with the server.
Definition: winscard_msg.c:174
INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID, uint64_t size, void *data_void)
Wrapper for the MessageSend() function.
Definition: winscard_msg.c:317
#define SCARD_F_COMM_ERROR
An internal communications error has been detected.
Definition: pcsclite.h:122
uint32_t command
one of the pcsc_msg_commands
Definition: winscard_msg.h:69
This handles abstract system level calls.
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
Definition: pcsclite.h:132
header structure for client/server message data exchange.
Definition: winscard_msg.h:66
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:451
This defines some structures and #defines to be used over the transport layer.
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:137
uint32_t size
size of the message excluding this header
Definition: winscard_msg.h:68
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.
Definition: winscard_msg.c:119
This keeps a list of defines for pcsc-lite.
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:353
#define SCARD_S_SUCCESS
error codes from http://msdn.microsoft.com/en-us/library/aa924526.aspx
Definition: pcsclite.h:103
This handles smart card reader communications.
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:195
This handles debugging.
#define SCARD_E_TIMEOUT
The user-specified timeout value has expired.
Definition: pcsclite.h:113