pcsc-lite  1.8.8
winscard_msg.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( http://www.linuxnet.com )
3  *
4  * Copyright (C) 2001-2004
5  * David Corcoran <corcoran@linuxnet.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  * $Id: winscard_msg.c 6441 2012-08-24 07:42:05Z rousseau $
12  */
13 
23 #include "config.h"
24 #include <fcntl.h>
25 #include <unistd.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <sys/socket.h>
29 #include <sys/time.h>
30 #include <sys/un.h>
31 #include <sys/ioctl.h>
32 #include <errno.h>
33 #include <stdio.h>
34 #include <time.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #ifdef HAVE_SYS_FILIO_H
38 #include <sys/filio.h>
39 #endif
40 
41 #include "misc.h"
42 #include "pcscd.h"
43 #include "winscard.h"
44 #include "debuglog.h"
45 #include "winscard_msg.h"
46 #include "sys_generic.h"
47 #include "utils.h"
48 #include "strlcpycat.h"
49 
50 #ifdef PCSCD
51 
52 /* functions used by pcscd only */
53 
54 #else
55 
56 /* functions used by libpcsclite only */
57 
58 char *getSocketName(void)
59 {
60  static char socketName[sizeof(struct sockaddr_un)];
61 
62  if ('\0' == socketName[0])
63  {
64  /* socket name not yet initialized */
65  char *socketNameEnv;
66 
67  socketNameEnv = getenv("PCSCLITE_CSOCK_NAME");
68  if (socketNameEnv)
69  strlcpy(socketName, socketNameEnv, sizeof(socketName));
70  else
71  strlcpy(socketName, PCSCLITE_CSOCK_NAME, sizeof(socketName));
72  }
73 
74  return socketName;
75 }
76 
90 INTERNAL int ClientSetupSession(uint32_t *pdwClientID)
91 {
92  struct sockaddr_un svc_addr;
93  int ret;
94  char *socketName;
95 
96  ret = socket(PF_UNIX, SOCK_STREAM, 0);
97  if (ret < 0)
98  {
99  Log2(PCSC_LOG_CRITICAL, "Error: create on client socket: %s",
100  strerror(errno));
101  return -1;
102  }
103  *pdwClientID = ret;
104 
105  socketName = getSocketName();
106  svc_addr.sun_family = AF_UNIX;
107  strncpy(svc_addr.sun_path, socketName, sizeof(svc_addr.sun_path));
108 
109  if (connect(*pdwClientID, (struct sockaddr *) &svc_addr,
110  sizeof(svc_addr.sun_family) + strlen(svc_addr.sun_path) + 1) < 0)
111  {
112  Log3(PCSC_LOG_CRITICAL, "Error: connect to client socket %s: %s",
113  socketName, strerror(errno));
114  (void)close(*pdwClientID);
115  return -1;
116  }
117 
118  ret = fcntl(*pdwClientID, F_GETFL, 0);
119  if (ret < 0)
120  {
121  Log3(PCSC_LOG_CRITICAL, "Error: cannot retrieve socket %s flags: %s",
122  socketName, strerror(errno));
123  (void)close(*pdwClientID);
124  return -1;
125  }
126 
127  if (fcntl(*pdwClientID, F_SETFL, ret | O_NONBLOCK) < 0)
128  {
129  Log3(PCSC_LOG_CRITICAL, "Error: cannot set socket %s nonblocking: %s",
130  socketName, strerror(errno));
131  (void)close(*pdwClientID);
132  return -1;
133  }
134 
135  return 0;
136 }
137 
145 INTERNAL int ClientCloseSession(uint32_t dwClientID)
146 {
147  return close(dwClientID);
148 }
149 
166 INTERNAL LONG MessageReceiveTimeout(uint32_t command, void *buffer_void,
167  uint64_t buffer_size, int32_t filedes, long timeOut)
168 {
169  char *buffer = buffer_void;
170 
171  /* default is success */
172  LONG retval = SCARD_S_SUCCESS;
173 
174  /* record the time when we started */
175  struct timeval start;
176 
177  /* how many bytes we must read */
178  size_t remaining = buffer_size;
179 
180  gettimeofday(&start, NULL);
181 
182  /* repeat until we get the whole message */
183  while (remaining > 0)
184  {
185  fd_set read_fd;
186  struct timeval timeout, now;
187  int selret;
188  long delta;
189 
190  gettimeofday(&now, NULL);
191  delta = time_sub(&now, &start);
192 
193  if (delta > timeOut*1000)
194  {
195  /* we already timed out */
196  retval = SCARD_E_TIMEOUT;
197  break;
198  }
199 
200  /* remaining time to wait */
201  delta = timeOut*1000 - delta;
202 
203  FD_ZERO(&read_fd);
204  FD_SET(filedes, &read_fd);
205 
206  timeout.tv_sec = delta/1000000;
207  timeout.tv_usec = delta - timeout.tv_sec*1000000;
208 
209  selret = select(filedes + 1, &read_fd, NULL, NULL, &timeout);
210 
211  /* try to read only when socket is readable */
212  if (selret > 0)
213  {
214  int readed;
215 
216  if (!FD_ISSET(filedes, &read_fd))
217  {
218  /* very strange situation. it should be an assert really */
219  retval = SCARD_F_COMM_ERROR;
220  break;
221  }
222  readed = read(filedes, buffer, remaining);
223 
224  if (readed > 0)
225  {
226  /* we got something */
227  buffer += readed;
228  remaining -= readed;
229  } else if (readed == 0)
230  {
231  /* peer closed the socket */
232  retval = SCARD_F_COMM_ERROR;
233  break;
234  } else
235  {
236  /* we ignore the signals and empty socket situations, all
237  * other errors are fatal */
238  if (errno != EINTR && errno != EAGAIN)
239  {
240  retval = SCARD_F_COMM_ERROR;
241  break;
242  }
243  }
244  } else if (selret == 0)
245  {
246  /* is the daemon still there? */
247  retval = SCardCheckDaemonAvailability();
248  if (retval != SCARD_S_SUCCESS)
249  {
250  /* timeout */
251  break;
252  }
253 
254  /* you need to set the env variable PCSCLITE_DEBUG=0 since
255  * this is logged on the client side and not on the pcscd
256  * side*/
257  Log2(PCSC_LOG_INFO, "Command 0x%X not yet finished", command);
258  } else
259  {
260  /* we ignore signals, all other errors are fatal */
261  if (errno != EINTR)
262  {
263  Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
264  strerror(errno));
265  retval = SCARD_F_COMM_ERROR;
266  break;
267  }
268  }
269  }
270 
271  return retval;
272 }
273 
288 INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID,
289  uint64_t size, void *data_void)
290 {
291  struct rxHeader header;
292  LONG ret;
293 
294  /* header */
295  header.command = command;
296  header.size = size;
297  ret = MessageSend(&header, sizeof(header), dwClientID);
298 
299  /* command */
300  if (size > 0)
301  ret = MessageSend(data_void, size, dwClientID);
302 
303  return ret;
304 }
305 
306 #endif
307 
308 /* functions used by pcscd and libpcsclite */
309 
324 INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size,
325  int32_t filedes)
326 {
327  char *buffer = buffer_void;
328 
329  /* default is success */
330  LONG retval = SCARD_S_SUCCESS;
331 
332  /* how many bytes remains to be written */
333  size_t remaining = buffer_size;
334 
335  /* repeat until all data is written */
336  while (remaining > 0)
337  {
338  fd_set write_fd;
339  int selret;
340 
341  FD_ZERO(&write_fd);
342  FD_SET(filedes, &write_fd);
343 
344  selret = select(filedes + 1, NULL, &write_fd, NULL, NULL);
345 
346  /* try to write only when the file descriptor is writable */
347  if (selret > 0)
348  {
349  int written;
350 
351  if (!FD_ISSET(filedes, &write_fd))
352  {
353  /* very strange situation. it should be an assert really */
354  retval = SCARD_F_COMM_ERROR;
355  break;
356  }
357  /* since we are a user library we can't play with signals
358  * The signals may already be used by the application */
359 #ifdef MSG_NOSIGNAL
360  /* Get EPIPE return code instead of SIGPIPE signal
361  * Works on Linux */
362  written = send(filedes, buffer, remaining, MSG_NOSIGNAL);
363 #else
364  /* we may get a SIGPIPE signal if the other side has closed */
365  written = write(filedes, buffer, remaining);
366 #endif
367 
368  if (written > 0)
369  {
370  /* we wrote something */
371  buffer += written;
372  remaining -= written;
373  } else if (written == 0)
374  {
375  /* peer closed the socket */
376  retval = SCARD_F_COMM_ERROR;
377  break;
378  } else
379  {
380  /* we ignore the signals and socket full situations, all
381  * other errors are fatal */
382  if (errno != EINTR && errno != EAGAIN)
383  {
384  retval = SCARD_E_NO_SERVICE;
385  break;
386  }
387  }
388  } else if (selret == 0)
389  {
390  /* timeout */
391  retval = SCARD_E_TIMEOUT;
392  break;
393  } else
394  {
395  /* ignore signals */
396  if (errno != EINTR)
397  {
398  Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
399  strerror(errno));
400  retval = SCARD_F_COMM_ERROR;
401  break;
402  }
403  }
404  }
405 
406  return retval;
407 }
408 
422 INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size,
423  int32_t filedes)
424 {
425  char *buffer = buffer_void;
426 
427  /* default is success */
428  LONG retval = SCARD_S_SUCCESS;
429 
430  /* how many bytes we must read */
431  size_t remaining = buffer_size;
432 
433  /* repeat until we get the whole message */
434  while (remaining > 0)
435  {
436  fd_set read_fd;
437  int selret;
438 
439  FD_ZERO(&read_fd);
440  FD_SET(filedes, &read_fd);
441 
442  selret = select(filedes + 1, &read_fd, NULL, NULL, NULL);
443 
444  /* try to read only when socket is readable */
445  if (selret > 0)
446  {
447  int readed;
448 
449  if (!FD_ISSET(filedes, &read_fd))
450  {
451  /* very strange situation. it should be an assert really */
452  retval = SCARD_F_COMM_ERROR;
453  break;
454  }
455  readed = read(filedes, buffer, remaining);
456 
457  if (readed > 0)
458  {
459  /* we got something */
460  buffer += readed;
461  remaining -= readed;
462  } else if (readed == 0)
463  {
464  /* peer closed the socket */
465  retval = SCARD_F_COMM_ERROR;
466  break;
467  } else
468  {
469  /* we ignore the signals and empty socket situations, all
470  * other errors are fatal */
471  if (errno != EINTR && errno != EAGAIN)
472  {
473  retval = SCARD_F_COMM_ERROR;
474  break;
475  }
476  }
477  }
478  else
479  {
480  /* we ignore signals, all other errors are fatal */
481  if (errno != EINTR)
482  {
483  Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
484  strerror(errno));
485  retval = SCARD_F_COMM_ERROR;
486  break;
487  }
488  }
489  }
490 
491  return retval;
492 }
493 
INTERNAL int ClientCloseSession(uint32_t dwClientID)
Closes the socket used by the client to communicate with the server.
Definition: winscard_msg.c:145
INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID, uint64_t size, void *data_void)
Wrapper for the MessageSend() function.
Definition: winscard_msg.c:288
#define SCARD_F_COMM_ERROR
An internal communications error has been detected.
Definition: pcsclite.h:99
uint32_t command
one of the pcsc_msg_commands
Definition: winscard_msg.h:46
This handles abstract system level calls.
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
Definition: pcsclite.h:109
header structure for client/server message data exchange.
Definition: winscard_msg.h:43
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:422
prototypes of strlcpy()/strlcat() imported from OpenBSD
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:106
uint32_t size
size of the message excluding this header
Definition: winscard_msg.h:45
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:90
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:324
#define SCARD_S_SUCCESS
error codes from http://msdn.microsoft.com/en-us/library/aa924526.aspx
Definition: pcsclite.h:80
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:166
This handles debugging.
#define SCARD_E_TIMEOUT
The user-specified timeout value has expired.
Definition: pcsclite.h:90