pcsc-lite 1.5.5
|
00001 /* 00002 * MUSCLE SmartCard Development ( http://www.linuxnet.com ) 00003 * 00004 * Copyright (C) 2001-2004 00005 * David Corcoran <corcoran@linuxnet.com> 00006 * Damien Sauveron <damien.sauveron@labri.fr> 00007 * Ludoic Rousseau <ludovic.rousseau@free.fr> 00008 * 00009 * $Id: winscard_msg.c 3250 2009-01-02 13:32:17Z rousseau $ 00010 */ 00011 00021 #include "config.h" 00022 #include <fcntl.h> 00023 #include <unistd.h> 00024 #include <sys/types.h> 00025 #include <sys/stat.h> 00026 #include <sys/socket.h> 00027 #include <sys/time.h> 00028 #include <sys/un.h> 00029 #include <sys/ioctl.h> 00030 #include <errno.h> 00031 #include <stdio.h> 00032 #include <time.h> 00033 #include <string.h> 00034 #ifdef HAVE_SYS_FILIO_H 00035 #include <sys/filio.h> 00036 #endif 00037 00038 #include "misc.h" 00039 #include "pcscd.h" 00040 #include "winscard.h" 00041 #include "debug.h" 00042 #include "winscard_msg.h" 00043 #include "sys_generic.h" 00044 #include "utils.h" 00045 00057 INTERNAL int32_t SHMClientRead(psharedSegmentMsg msgStruct, uint32_t dwClientID, int32_t blockamount) 00058 { 00059 return SHMMessageReceive(msgStruct, sizeof(*msgStruct), dwClientID, blockamount); 00060 } 00061 00075 INTERNAL int SHMClientSetupSession(uint32_t *pdwClientID) 00076 { 00077 struct sockaddr_un svc_addr; 00078 int one; 00079 int ret; 00080 00081 ret = socket(AF_UNIX, SOCK_STREAM, 0); 00082 if (ret < 0) 00083 { 00084 Log2(PCSC_LOG_CRITICAL, "Error: create on client socket: %s", 00085 strerror(errno)); 00086 return -1; 00087 } 00088 *pdwClientID = ret; 00089 00090 svc_addr.sun_family = AF_UNIX; 00091 strncpy(svc_addr.sun_path, PCSCLITE_CSOCK_NAME, 00092 sizeof(svc_addr.sun_path)); 00093 00094 if (connect(*pdwClientID, (struct sockaddr *) &svc_addr, 00095 sizeof(svc_addr.sun_family) + strlen(svc_addr.sun_path) + 1) < 0) 00096 { 00097 Log3(PCSC_LOG_CRITICAL, "Error: connect to client socket %s: %s", 00098 PCSCLITE_CSOCK_NAME, strerror(errno)); 00099 (void)SYS_CloseFile(*pdwClientID); 00100 return -1; 00101 } 00102 00103 one = 1; 00104 if (ioctl(*pdwClientID, FIONBIO, &one) < 0) 00105 { 00106 Log3(PCSC_LOG_CRITICAL, "Error: cannot set socket %s nonblocking: %s", 00107 PCSCLITE_CSOCK_NAME, strerror(errno)); 00108 (void)SYS_CloseFile(*pdwClientID); 00109 return -1; 00110 } 00111 00112 return 0; 00113 } 00114 00122 INTERNAL int SHMClientCloseSession(uint32_t dwClientID) 00123 { 00124 (void)SYS_CloseFile(dwClientID); 00125 return 0; 00126 } 00127 00143 INTERNAL int32_t SHMMessageSend(void *buffer_void, uint64_t buffer_size, 00144 int32_t filedes, int32_t blockAmount) 00145 { 00146 char *buffer = buffer_void; 00147 00148 /* 00149 * default is success 00150 */ 00151 int retval = 0; 00152 /* 00153 * record the time when we started 00154 */ 00155 time_t start = time(0); 00156 /* 00157 * how many bytes remains to be written 00158 */ 00159 size_t remaining = buffer_size; 00160 00161 /* 00162 * repeat until all data is written 00163 */ 00164 while (remaining > 0) 00165 { 00166 fd_set write_fd; 00167 struct timeval timeout; 00168 int selret; 00169 00170 FD_ZERO(&write_fd); 00171 FD_SET(filedes, &write_fd); 00172 00173 timeout.tv_usec = 0; 00174 if ((timeout.tv_sec = start + blockAmount - time(0)) < 0) 00175 { 00176 /* 00177 * we already timed out 00178 */ 00179 retval = -1; 00180 break; 00181 } 00182 00183 selret = select(filedes + 1, NULL, &write_fd, NULL, &timeout); 00184 00185 /* 00186 * try to write only when the file descriptor is writable 00187 */ 00188 if (selret > 0) 00189 { 00190 int written; 00191 00192 if (!FD_ISSET(filedes, &write_fd)) 00193 { 00194 /* 00195 * very strange situation. it should be an assert really 00196 */ 00197 retval = -1; 00198 break; 00199 } 00200 written = write(filedes, buffer, remaining); 00201 00202 if (written > 0) 00203 { 00204 /* 00205 * we wrote something 00206 */ 00207 buffer += written; 00208 remaining -= written; 00209 } else if (written == 0) 00210 { 00211 /* 00212 * peer closed the socket 00213 */ 00214 retval = -1; 00215 break; 00216 } else 00217 { 00218 /* 00219 * we ignore the signals and socket full situations, all 00220 * other errors are fatal 00221 */ 00222 if (errno != EINTR && errno != EAGAIN) 00223 { 00224 retval = -1; 00225 break; 00226 } 00227 } 00228 } else if (selret == 0) 00229 { 00230 /* 00231 * timeout 00232 */ 00233 retval = -1; 00234 break; 00235 } else 00236 { 00237 /* 00238 * ignore signals 00239 */ 00240 if (errno != EINTR) 00241 { 00242 Log2(PCSC_LOG_ERROR, "select returns with failure: %s", 00243 strerror(errno)); 00244 retval = -1; 00245 break; 00246 } 00247 } 00248 } 00249 00250 return retval; 00251 } 00252 00268 INTERNAL int32_t SHMMessageReceive(void *buffer_void, uint64_t buffer_size, 00269 int32_t filedes, int32_t blockAmount) 00270 { 00271 char *buffer = buffer_void; 00272 00273 /* 00274 * default is success 00275 */ 00276 int retval = 0; 00277 /* 00278 * record the time when we started 00279 */ 00280 time_t start = time(0); 00281 /* 00282 * how many bytes we must read 00283 */ 00284 size_t remaining = buffer_size; 00285 00286 /* 00287 * repeat until we get the whole message 00288 */ 00289 while (remaining > 0) 00290 { 00291 fd_set read_fd; 00292 struct timeval timeout; 00293 int selret; 00294 00295 FD_ZERO(&read_fd); 00296 FD_SET(filedes, &read_fd); 00297 00298 timeout.tv_usec = 0; 00299 if ((timeout.tv_sec = start + blockAmount - time(0)) < 0) 00300 { 00301 /* 00302 * we already timed out 00303 */ 00304 retval = -1; 00305 break; 00306 } 00307 00308 selret = select(filedes + 1, &read_fd, NULL, NULL, &timeout); 00309 00310 /* 00311 * try to read only when socket is readable 00312 */ 00313 if (selret > 0) 00314 { 00315 int readed; 00316 00317 if (!FD_ISSET(filedes, &read_fd)) 00318 { 00319 /* 00320 * very strange situation. it should be an assert really 00321 */ 00322 retval = -1; 00323 break; 00324 } 00325 readed = read(filedes, buffer, remaining); 00326 00327 if (readed > 0) 00328 { 00329 /* 00330 * we got something 00331 */ 00332 buffer += readed; 00333 remaining -= readed; 00334 } else if (readed == 0) 00335 { 00336 /* 00337 * peer closed the socket 00338 */ 00339 retval = -1; 00340 break; 00341 } else 00342 { 00343 /* 00344 * we ignore the signals and empty socket situations, all 00345 * other errors are fatal 00346 */ 00347 if (errno != EINTR && errno != EAGAIN) 00348 { 00349 retval = -1; 00350 break; 00351 } 00352 } 00353 } else if (selret == 0) 00354 { 00355 #ifdef PCSCD 00356 /* 00357 * timeout 00358 */ 00359 retval = -1; 00360 break; 00361 #else 00362 /* is the daemon still there? */ 00363 if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS) 00364 { 00365 /* 00366 * timeout 00367 */ 00368 retval = -1; 00369 break; 00370 } 00371 00372 /* the command is extra slow so we keep waiting */ 00373 start = time(0); 00374 00375 /* you need to set the env variable PCSCLITE_DEBUG=0 since this is 00376 * logged on the client side and not on the pcscd side*/ 00377 Log1(PCSC_LOG_INFO, "Command not yet finished"); 00378 #endif 00379 } else 00380 { 00381 /* 00382 * we ignore signals, all other errors are fatal 00383 */ 00384 if (errno != EINTR) 00385 { 00386 Log2(PCSC_LOG_ERROR, "select returns with failure: %s", 00387 strerror(errno)); 00388 retval = -1; 00389 break; 00390 } 00391 } 00392 } 00393 00394 return retval; 00395 } 00396 00412 INTERNAL int32_t WrapSHMWrite(uint32_t command, uint32_t dwClientID, 00413 uint64_t size, uint32_t blockAmount, void *data_void) 00414 { 00415 char *data = data_void; 00416 00417 sharedSegmentMsg msgStruct; 00418 int ret; 00419 00420 /* 00421 * Set the appropriate packet parameters 00422 */ 00423 00424 memset(&msgStruct, 0, sizeof(msgStruct)); 00425 msgStruct.mtype = CMD_FUNCTION; 00426 msgStruct.user_id = SYS_GetUID(); 00427 msgStruct.group_id = SYS_GetGID(); 00428 msgStruct.command = command; 00429 msgStruct.date = time(NULL); 00430 memset(msgStruct.key, 0, sizeof(msgStruct.key)); 00431 if ((SCARD_TRANSMIT_EXTENDED == command) 00432 || (SCARD_CONTROL_EXTENDED == command)) 00433 { 00434 /* first block */ 00435 if (size > sizeof(msgStruct.data)) 00436 memcpy(msgStruct.data, data, sizeof(msgStruct.data)); 00437 else 00438 { 00439 memcpy(msgStruct.data, data, size); 00440 memset(msgStruct.data+size, 0, sizeof(msgStruct.data)-size); 00441 } 00442 00443 ret = SHMMessageSend(&msgStruct, sizeof(msgStruct), dwClientID, 00444 blockAmount); 00445 00446 /* do not send an empty second block */ 00447 if ((0 == ret) && (size > sizeof(msgStruct.data))) 00448 { 00449 /* second block */ 00450 ret = SHMMessageSend(data+sizeof(msgStruct.data), 00451 size-sizeof(msgStruct.data), dwClientID, blockAmount); 00452 } 00453 } 00454 else 00455 { 00456 memcpy(msgStruct.data, data, size); 00457 00458 ret = SHMMessageSend(&msgStruct, sizeof(msgStruct), dwClientID, 00459 blockAmount); 00460 } 00461 00462 if (SCARD_TRANSMIT == command) 00463 /* clean APDU buffer to remove any possible PIN or secret value */ 00464 memset(msgStruct.data, 0, min(size, sizeof(msgStruct.data))); 00465 00466 return ret; 00467 } 00468 00478 INTERNAL void SHMCleanupSharedSegment(int sockValue, const char *pcFilePath) 00479 { 00480 (void)SYS_CloseFile(sockValue); 00481 (void)SYS_RemoveFile(pcFilePath); 00482 } 00483