pcsc-lite
1.8.2
|
00001 /* 00002 * MUSCLE SmartCard Development ( http://www.linuxnet.com ) 00003 * 00004 * Copyright (C) 2001-2004 00005 * David Corcoran <corcoran@linuxnet.com> 00006 * Copyright (C) 2003-2004 00007 * Damien Sauveron <damien.sauveron@labri.fr> 00008 * Copyright (C) 2002-2010 00009 * Ludovic Rousseau <ludovic.rousseau@free.fr> 00010 * 00011 * $Id: winscard_msg.c 5867 2011-07-09 11:50:16Z rousseau $ 00012 */ 00013 00023 #include "config.h" 00024 #include <fcntl.h> 00025 #include <unistd.h> 00026 #include <sys/types.h> 00027 #include <sys/stat.h> 00028 #include <sys/socket.h> 00029 #include <sys/time.h> 00030 #include <sys/un.h> 00031 #include <sys/ioctl.h> 00032 #include <errno.h> 00033 #include <stdio.h> 00034 #include <time.h> 00035 #include <string.h> 00036 #include <stdlib.h> 00037 #ifdef HAVE_SYS_FILIO_H 00038 #include <sys/filio.h> 00039 #endif 00040 00041 #include "misc.h" 00042 #include "pcscd.h" 00043 #include "winscard.h" 00044 #include "debuglog.h" 00045 #include "winscard_msg.h" 00046 #include "sys_generic.h" 00047 #include "utils.h" 00048 #include "strlcpycat.h" 00049 00050 #ifdef PCSCD 00051 00052 /* functions used by pcscd only */ 00053 00054 #else 00055 00056 /* functions used by libpcsclite only */ 00057 00058 char *getSocketName(void) 00059 { 00060 static char socketName[sizeof(struct sockaddr_un)]; 00061 00062 if ('\0' == socketName[0]) 00063 { 00064 /* socket name not yet initialized */ 00065 char *socketNameEnv; 00066 00067 socketNameEnv = getenv("PCSCLITE_CSOCK_NAME"); 00068 if (socketNameEnv) 00069 strlcpy(socketName, socketNameEnv, sizeof(socketName)); 00070 else 00071 strlcpy(socketName, PCSCLITE_CSOCK_NAME, sizeof(socketName)); 00072 } 00073 00074 return socketName; 00075 } 00076 00090 INTERNAL int ClientSetupSession(uint32_t *pdwClientID) 00091 { 00092 struct sockaddr_un svc_addr; 00093 int one; 00094 int ret; 00095 char *socketName; 00096 00097 ret = socket(PF_UNIX, SOCK_STREAM, 0); 00098 if (ret < 0) 00099 { 00100 Log2(PCSC_LOG_CRITICAL, "Error: create on client socket: %s", 00101 strerror(errno)); 00102 return -1; 00103 } 00104 *pdwClientID = ret; 00105 00106 socketName = getSocketName(); 00107 svc_addr.sun_family = AF_UNIX; 00108 strncpy(svc_addr.sun_path, socketName, sizeof(svc_addr.sun_path)); 00109 00110 if (connect(*pdwClientID, (struct sockaddr *) &svc_addr, 00111 sizeof(svc_addr.sun_family) + strlen(svc_addr.sun_path) + 1) < 0) 00112 { 00113 Log3(PCSC_LOG_CRITICAL, "Error: connect to client socket %s: %s", 00114 socketName, strerror(errno)); 00115 (void)close(*pdwClientID); 00116 return -1; 00117 } 00118 00119 one = 1; 00120 if (ioctl(*pdwClientID, FIONBIO, &one) < 0) 00121 { 00122 Log3(PCSC_LOG_CRITICAL, "Error: cannot set socket %s nonblocking: %s", 00123 socketName, strerror(errno)); 00124 (void)close(*pdwClientID); 00125 return -1; 00126 } 00127 00128 return 0; 00129 } 00130 00138 INTERNAL int ClientCloseSession(uint32_t dwClientID) 00139 { 00140 return close(dwClientID); 00141 } 00142 00159 INTERNAL LONG MessageReceiveTimeout(uint32_t command, void *buffer_void, 00160 uint64_t buffer_size, int32_t filedes, long timeOut) 00161 { 00162 char *buffer = buffer_void; 00163 00164 /* default is success */ 00165 LONG retval = SCARD_S_SUCCESS; 00166 00167 /* record the time when we started */ 00168 struct timeval start; 00169 00170 /* how many bytes we must read */ 00171 size_t remaining = buffer_size; 00172 00173 gettimeofday(&start, NULL); 00174 00175 /* repeat until we get the whole message */ 00176 while (remaining > 0) 00177 { 00178 fd_set read_fd; 00179 struct timeval timeout, now; 00180 int selret; 00181 long delta; 00182 00183 gettimeofday(&now, NULL); 00184 delta = time_sub(&now, &start); 00185 00186 if (delta > timeOut*1000) 00187 { 00188 /* we already timed out */ 00189 retval = SCARD_E_TIMEOUT; 00190 break; 00191 } 00192 00193 /* remaining time to wait */ 00194 delta = timeOut*1000 - delta; 00195 00196 FD_ZERO(&read_fd); 00197 FD_SET(filedes, &read_fd); 00198 00199 timeout.tv_sec = delta/1000000; 00200 timeout.tv_usec = delta - timeout.tv_sec*1000000; 00201 00202 selret = select(filedes + 1, &read_fd, NULL, NULL, &timeout); 00203 00204 /* try to read only when socket is readable */ 00205 if (selret > 0) 00206 { 00207 int readed; 00208 00209 if (!FD_ISSET(filedes, &read_fd)) 00210 { 00211 /* very strange situation. it should be an assert really */ 00212 retval = SCARD_F_COMM_ERROR; 00213 break; 00214 } 00215 readed = read(filedes, buffer, remaining); 00216 00217 if (readed > 0) 00218 { 00219 /* we got something */ 00220 buffer += readed; 00221 remaining -= readed; 00222 } else if (readed == 0) 00223 { 00224 /* peer closed the socket */ 00225 retval = SCARD_F_COMM_ERROR; 00226 break; 00227 } else 00228 { 00229 /* we ignore the signals and empty socket situations, all 00230 * other errors are fatal */ 00231 if (errno != EINTR && errno != EAGAIN) 00232 { 00233 retval = SCARD_F_COMM_ERROR; 00234 break; 00235 } 00236 } 00237 } else if (selret == 0) 00238 { 00239 /* is the daemon still there? */ 00240 retval = SCardCheckDaemonAvailability(); 00241 if (retval != SCARD_S_SUCCESS) 00242 { 00243 /* timeout */ 00244 break; 00245 } 00246 00247 /* you need to set the env variable PCSCLITE_DEBUG=0 since 00248 * this is logged on the client side and not on the pcscd 00249 * side*/ 00250 Log2(PCSC_LOG_INFO, "Command 0x%X not yet finished", command); 00251 } else 00252 { 00253 /* we ignore signals, all other errors are fatal */ 00254 if (errno != EINTR) 00255 { 00256 Log2(PCSC_LOG_ERROR, "select returns with failure: %s", 00257 strerror(errno)); 00258 retval = SCARD_F_COMM_ERROR; 00259 break; 00260 } 00261 } 00262 } 00263 00264 return retval; 00265 } 00266 00281 INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID, 00282 uint64_t size, void *data_void) 00283 { 00284 struct rxHeader header; 00285 LONG ret; 00286 00287 /* header */ 00288 header.command = command; 00289 header.size = size; 00290 ret = MessageSend(&header, sizeof(header), dwClientID); 00291 00292 /* command */ 00293 if (size > 0) 00294 ret = MessageSend(data_void, size, dwClientID); 00295 00296 return ret; 00297 } 00298 00299 #endif 00300 00301 /* functions used by pcscd and libpcsclite */ 00302 00317 INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size, 00318 int32_t filedes) 00319 { 00320 char *buffer = buffer_void; 00321 00322 /* default is success */ 00323 LONG retval = SCARD_S_SUCCESS; 00324 00325 /* how many bytes remains to be written */ 00326 size_t remaining = buffer_size; 00327 00328 /* repeat until all data is written */ 00329 while (remaining > 0) 00330 { 00331 fd_set write_fd; 00332 int selret; 00333 00334 FD_ZERO(&write_fd); 00335 FD_SET(filedes, &write_fd); 00336 00337 selret = select(filedes + 1, NULL, &write_fd, NULL, NULL); 00338 00339 /* try to write only when the file descriptor is writable */ 00340 if (selret > 0) 00341 { 00342 int written; 00343 00344 if (!FD_ISSET(filedes, &write_fd)) 00345 { 00346 /* very strange situation. it should be an assert really */ 00347 retval = SCARD_F_COMM_ERROR; 00348 break; 00349 } 00350 /* since we are a user library we can't play with signals 00351 * The signals may already be used by the application */ 00352 #ifdef MSG_NOSIGNAL 00353 /* Get EPIPE return code instead of SIGPIPE signal 00354 * Works on Linux */ 00355 written = send(filedes, buffer, remaining, MSG_NOSIGNAL); 00356 #else 00357 /* we may get a SIGPIPE signal if the other side has closed */ 00358 written = write(filedes, buffer, remaining); 00359 #endif 00360 00361 if (written > 0) 00362 { 00363 /* we wrote something */ 00364 buffer += written; 00365 remaining -= written; 00366 } else if (written == 0) 00367 { 00368 /* peer closed the socket */ 00369 retval = SCARD_F_COMM_ERROR; 00370 break; 00371 } else 00372 { 00373 /* we ignore the signals and socket full situations, all 00374 * other errors are fatal */ 00375 if (errno != EINTR && errno != EAGAIN) 00376 { 00377 retval = SCARD_E_NO_SERVICE; 00378 break; 00379 } 00380 } 00381 } else if (selret == 0) 00382 { 00383 /* timeout */ 00384 retval = SCARD_E_TIMEOUT; 00385 break; 00386 } else 00387 { 00388 /* ignore signals */ 00389 if (errno != EINTR) 00390 { 00391 Log2(PCSC_LOG_ERROR, "select returns with failure: %s", 00392 strerror(errno)); 00393 retval = SCARD_F_COMM_ERROR; 00394 break; 00395 } 00396 } 00397 } 00398 00399 return retval; 00400 } 00401 00415 INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size, 00416 int32_t filedes) 00417 { 00418 char *buffer = buffer_void; 00419 00420 /* default is success */ 00421 LONG retval = SCARD_S_SUCCESS; 00422 00423 /* how many bytes we must read */ 00424 size_t remaining = buffer_size; 00425 00426 /* repeat until we get the whole message */ 00427 while (remaining > 0) 00428 { 00429 fd_set read_fd; 00430 int selret; 00431 00432 FD_ZERO(&read_fd); 00433 FD_SET(filedes, &read_fd); 00434 00435 selret = select(filedes + 1, &read_fd, NULL, NULL, NULL); 00436 00437 /* try to read only when socket is readable */ 00438 if (selret > 0) 00439 { 00440 int readed; 00441 00442 if (!FD_ISSET(filedes, &read_fd)) 00443 { 00444 /* very strange situation. it should be an assert really */ 00445 retval = SCARD_F_COMM_ERROR; 00446 break; 00447 } 00448 readed = read(filedes, buffer, remaining); 00449 00450 if (readed > 0) 00451 { 00452 /* we got something */ 00453 buffer += readed; 00454 remaining -= readed; 00455 } else if (readed == 0) 00456 { 00457 /* peer closed the socket */ 00458 retval = SCARD_F_COMM_ERROR; 00459 break; 00460 } else 00461 { 00462 /* we ignore the signals and empty socket situations, all 00463 * other errors are fatal */ 00464 if (errno != EINTR && errno != EAGAIN) 00465 { 00466 retval = SCARD_F_COMM_ERROR; 00467 break; 00468 } 00469 } 00470 } 00471 else 00472 { 00473 /* we ignore signals, all other errors are fatal */ 00474 if (errno != EINTR) 00475 { 00476 Log2(PCSC_LOG_ERROR, "select returns with failure: %s", 00477 strerror(errno)); 00478 retval = SCARD_F_COMM_ERROR; 00479 break; 00480 } 00481 } 00482 } 00483 00484 return retval; 00485 } 00486