winscard_msg.c

Go to the documentation of this file.
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 

Generated on Mon Aug 17 01:00:12 2009 for pcsc-lite by  doxygen 1.5.9