pcsc-lite  1.8.3
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 5867 2011-07-09 11:50:16Z 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 one;
94  int ret;
95  char *socketName;
96 
97  ret = socket(PF_UNIX, SOCK_STREAM, 0);
98  if (ret < 0)
99  {
100  Log2(PCSC_LOG_CRITICAL, "Error: create on client socket: %s",
101  strerror(errno));
102  return -1;
103  }
104  *pdwClientID = ret;
105 
106  socketName = getSocketName();
107  svc_addr.sun_family = AF_UNIX;
108  strncpy(svc_addr.sun_path, socketName, sizeof(svc_addr.sun_path));
109 
110  if (connect(*pdwClientID, (struct sockaddr *) &svc_addr,
111  sizeof(svc_addr.sun_family) + strlen(svc_addr.sun_path) + 1) < 0)
112  {
113  Log3(PCSC_LOG_CRITICAL, "Error: connect to client socket %s: %s",
114  socketName, strerror(errno));
115  (void)close(*pdwClientID);
116  return -1;
117  }
118 
119  one = 1;
120  if (ioctl(*pdwClientID, FIONBIO, &one) < 0)
121  {
122  Log3(PCSC_LOG_CRITICAL, "Error: cannot set socket %s nonblocking: %s",
123  socketName, strerror(errno));
124  (void)close(*pdwClientID);
125  return -1;
126  }
127 
128  return 0;
129 }
130 
138 INTERNAL int ClientCloseSession(uint32_t dwClientID)
139 {
140  return close(dwClientID);
141 }
142 
159 INTERNAL LONG MessageReceiveTimeout(uint32_t command, void *buffer_void,
160  uint64_t buffer_size, int32_t filedes, long timeOut)
161 {
162  char *buffer = buffer_void;
163 
164  /* default is success */
165  LONG retval = SCARD_S_SUCCESS;
166 
167  /* record the time when we started */
168  struct timeval start;
169 
170  /* how many bytes we must read */
171  size_t remaining = buffer_size;
172 
173  gettimeofday(&start, NULL);
174 
175  /* repeat until we get the whole message */
176  while (remaining > 0)
177  {
178  fd_set read_fd;
179  struct timeval timeout, now;
180  int selret;
181  long delta;
182 
183  gettimeofday(&now, NULL);
184  delta = time_sub(&now, &start);
185 
186  if (delta > timeOut*1000)
187  {
188  /* we already timed out */
189  retval = SCARD_E_TIMEOUT;
190  break;
191  }
192 
193  /* remaining time to wait */
194  delta = timeOut*1000 - delta;
195 
196  FD_ZERO(&read_fd);
197  FD_SET(filedes, &read_fd);
198 
199  timeout.tv_sec = delta/1000000;
200  timeout.tv_usec = delta - timeout.tv_sec*1000000;
201 
202  selret = select(filedes + 1, &read_fd, NULL, NULL, &timeout);
203 
204  /* try to read only when socket is readable */
205  if (selret > 0)
206  {
207  int readed;
208 
209  if (!FD_ISSET(filedes, &read_fd))
210  {
211  /* very strange situation. it should be an assert really */
212  retval = SCARD_F_COMM_ERROR;
213  break;
214  }
215  readed = read(filedes, buffer, remaining);
216 
217  if (readed > 0)
218  {
219  /* we got something */
220  buffer += readed;
221  remaining -= readed;
222  } else if (readed == 0)
223  {
224  /* peer closed the socket */
225  retval = SCARD_F_COMM_ERROR;
226  break;
227  } else
228  {
229  /* we ignore the signals and empty socket situations, all
230  * other errors are fatal */
231  if (errno != EINTR && errno != EAGAIN)
232  {
233  retval = SCARD_F_COMM_ERROR;
234  break;
235  }
236  }
237  } else if (selret == 0)
238  {
239  /* is the daemon still there? */
240  retval = SCardCheckDaemonAvailability();
241  if (retval != SCARD_S_SUCCESS)
242  {
243  /* timeout */
244  break;
245  }
246 
247  /* you need to set the env variable PCSCLITE_DEBUG=0 since
248  * this is logged on the client side and not on the pcscd
249  * side*/
250  Log2(PCSC_LOG_INFO, "Command 0x%X not yet finished", command);
251  } else
252  {
253  /* we ignore signals, all other errors are fatal */
254  if (errno != EINTR)
255  {
256  Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
257  strerror(errno));
258  retval = SCARD_F_COMM_ERROR;
259  break;
260  }
261  }
262  }
263 
264  return retval;
265 }
266 
281 INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID,
282  uint64_t size, void *data_void)
283 {
284  struct rxHeader header;
285  LONG ret;
286 
287  /* header */
288  header.command = command;
289  header.size = size;
290  ret = MessageSend(&header, sizeof(header), dwClientID);
291 
292  /* command */
293  if (size > 0)
294  ret = MessageSend(data_void, size, dwClientID);
295 
296  return ret;
297 }
298 
299 #endif
300 
301 /* functions used by pcscd and libpcsclite */
302 
317 INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size,
318  int32_t filedes)
319 {
320  char *buffer = buffer_void;
321 
322  /* default is success */
323  LONG retval = SCARD_S_SUCCESS;
324 
325  /* how many bytes remains to be written */
326  size_t remaining = buffer_size;
327 
328  /* repeat until all data is written */
329  while (remaining > 0)
330  {
331  fd_set write_fd;
332  int selret;
333 
334  FD_ZERO(&write_fd);
335  FD_SET(filedes, &write_fd);
336 
337  selret = select(filedes + 1, NULL, &write_fd, NULL, NULL);
338 
339  /* try to write only when the file descriptor is writable */
340  if (selret > 0)
341  {
342  int written;
343 
344  if (!FD_ISSET(filedes, &write_fd))
345  {
346  /* very strange situation. it should be an assert really */
347  retval = SCARD_F_COMM_ERROR;
348  break;
349  }
350  /* since we are a user library we can't play with signals
351  * The signals may already be used by the application */
352 #ifdef MSG_NOSIGNAL
353  /* Get EPIPE return code instead of SIGPIPE signal
354  * Works on Linux */
355  written = send(filedes, buffer, remaining, MSG_NOSIGNAL);
356 #else
357  /* we may get a SIGPIPE signal if the other side has closed */
358  written = write(filedes, buffer, remaining);
359 #endif
360 
361  if (written > 0)
362  {
363  /* we wrote something */
364  buffer += written;
365  remaining -= written;
366  } else if (written == 0)
367  {
368  /* peer closed the socket */
369  retval = SCARD_F_COMM_ERROR;
370  break;
371  } else
372  {
373  /* we ignore the signals and socket full situations, all
374  * other errors are fatal */
375  if (errno != EINTR && errno != EAGAIN)
376  {
377  retval = SCARD_E_NO_SERVICE;
378  break;
379  }
380  }
381  } else if (selret == 0)
382  {
383  /* timeout */
384  retval = SCARD_E_TIMEOUT;
385  break;
386  } else
387  {
388  /* ignore signals */
389  if (errno != EINTR)
390  {
391  Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
392  strerror(errno));
393  retval = SCARD_F_COMM_ERROR;
394  break;
395  }
396  }
397  }
398 
399  return retval;
400 }
401 
415 INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size,
416  int32_t filedes)
417 {
418  char *buffer = buffer_void;
419 
420  /* default is success */
421  LONG retval = SCARD_S_SUCCESS;
422 
423  /* how many bytes we must read */
424  size_t remaining = buffer_size;
425 
426  /* repeat until we get the whole message */
427  while (remaining > 0)
428  {
429  fd_set read_fd;
430  int selret;
431 
432  FD_ZERO(&read_fd);
433  FD_SET(filedes, &read_fd);
434 
435  selret = select(filedes + 1, &read_fd, NULL, NULL, NULL);
436 
437  /* try to read only when socket is readable */
438  if (selret > 0)
439  {
440  int readed;
441 
442  if (!FD_ISSET(filedes, &read_fd))
443  {
444  /* very strange situation. it should be an assert really */
445  retval = SCARD_F_COMM_ERROR;
446  break;
447  }
448  readed = read(filedes, buffer, remaining);
449 
450  if (readed > 0)
451  {
452  /* we got something */
453  buffer += readed;
454  remaining -= readed;
455  } else if (readed == 0)
456  {
457  /* peer closed the socket */
458  retval = SCARD_F_COMM_ERROR;
459  break;
460  } else
461  {
462  /* we ignore the signals and empty socket situations, all
463  * other errors are fatal */
464  if (errno != EINTR && errno != EAGAIN)
465  {
466  retval = SCARD_F_COMM_ERROR;
467  break;
468  }
469  }
470  }
471  else
472  {
473  /* we ignore signals, all other errors are fatal */
474  if (errno != EINTR)
475  {
476  Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
477  strerror(errno));
478  retval = SCARD_F_COMM_ERROR;
479  break;
480  }
481  }
482  }
483 
484  return retval;
485 }
486