00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00020 #include "config.h"
00021 #include <time.h>
00022 #include <syslog.h>
00023 #include <signal.h>
00024 #include <sys/types.h>
00025 #include <sys/stat.h>
00026 #include <errno.h>
00027 #include <stdio.h>
00028 #include <unistd.h>
00029 #include <stdlib.h>
00030 #include <string.h>
00031 #ifdef HAVE_GETOPT_H
00032 #include <getopt.h>
00033 #endif
00034
00035 #include "misc.h"
00036 #include "pcsclite.h"
00037 #include "debuglog.h"
00038 #include "winscard_msg.h"
00039 #include "winscard_svc.h"
00040 #include "sys_generic.h"
00041 #include "thread_generic.h"
00042 #include "hotplug.h"
00043 #include "readerfactory.h"
00044 #include "configfile.h"
00045 #include "powermgt_generic.h"
00046
00047 #ifndef TRUE
00048 #define TRUE 1
00049 #define FALSE 0
00050 #endif
00051
00052 char AraKiri = FALSE;
00053 static char Init = TRUE;
00054 extern char ReCheckSerialReaders;
00055
00056
00057
00058
00059 void SVCServiceRunLoop(void);
00060 void SVCClientCleanup(psharedSegmentMsg);
00061 void at_exit(void);
00062 void clean_temp_files(void);
00063 void signal_reload(int sig);
00064 void signal_trap(int);
00065 void print_version (void);
00066 void print_usage (char const * const);
00067
00068 PCSCLITE_MUTEX usbNotifierMutex;
00069
00070
00071
00072
00073 void SVCClientCleanup(psharedSegmentMsg msgStruct)
00074 {
00075
00076
00077
00078 }
00079
00088 void SVCServiceRunLoop(void)
00089 {
00090 int rsp;
00091 LONG rv;
00092 DWORD dwClientID;
00093
00094 rsp = 0;
00095 rv = 0;
00096
00097
00098
00099
00100 rsp = SHMInitializeCommonSegment();
00101
00102 if (rsp == -1)
00103 {
00104 Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
00105 exit(-1);
00106 }
00107
00108
00109
00110
00111 rv = ContextsInitialize();
00112
00113 if (rv == -1)
00114 {
00115 Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
00116 exit(-1);
00117 }
00118
00119
00120
00121
00122
00123 signal(SIGALRM, SIG_IGN);
00124 signal(SIGPIPE, SIG_IGN);
00125 signal(SIGHUP, SIG_IGN);
00126
00127
00128
00129
00130
00131 rsp = SYS_MutexInit(&usbNotifierMutex);
00132
00133
00134
00135
00136 HPSearchHotPluggables();
00137 HPRegisterForHotplugEvents();
00138
00139
00140
00141
00142 PMRegisterForPowerEvents();
00143
00144 while (TRUE)
00145 {
00146
00147 switch (rsp = SHMProcessEventsServer(&dwClientID, 0))
00148 {
00149
00150 case 0:
00151 Log2(PCSC_LOG_DEBUG, "A new context thread creation is requested: %d", dwClientID);
00152 rv = CreateContextThread(&dwClientID);
00153
00154 if (rv != SCARD_S_SUCCESS)
00155 {
00156 Log1(PCSC_LOG_ERROR, "Problem during the context thread creation");
00157 AraKiri = TRUE;
00158 }
00159
00160 break;
00161
00162 case 2:
00163
00164
00165
00166
00167
00168 break;
00169
00170 case -1:
00171
00172 if ((!AraKiri) && (!ReCheckSerialReaders))
00173 Log1(PCSC_LOG_ERROR, "Error in SHMProcessEventsServer");
00174 break;
00175
00176 default:
00177 Log2(PCSC_LOG_ERROR, "SHMProcessEventsServer unknown retval: %d",
00178 rsp);
00179 break;
00180 }
00181
00182 if (AraKiri)
00183 {
00184
00185 HPStopHotPluggables();
00186 SYS_Sleep(1);
00187
00188
00189 RFCleanupReaders(1);
00190 }
00191 }
00192 }
00193
00194 int main(int argc, char **argv)
00195 {
00196 int rv;
00197 char setToForeground;
00198 char *newReaderConfig;
00199 struct stat fStatBuf;
00200 int opt;
00201 #ifdef HAVE_GETOPT_LONG
00202 int option_index = 0;
00203 static struct option long_options[] = {
00204 {"config", 1, 0, 'c'},
00205 {"foreground", 0, 0, 'f'},
00206 {"help", 0, 0, 'h'},
00207 {"version", 0, 0, 'v'},
00208 {"apdu", 0, 0, 'a'},
00209 {"debug", 0, 0, 'd'},
00210 {"info", 0, 0, 0},
00211 {"error", 0, 0, 'e'},
00212 {"critical", 0, 0, 'C'},
00213 {0, 0, 0, 0}
00214 };
00215 #endif
00216
00217 rv = 0;
00218 newReaderConfig = 0;
00219 setToForeground = FALSE;
00220
00221
00222
00223
00224 if (strcmp(PCSCLITE_VERSION_NUMBER, VERSION) != 0)
00225 {
00226 printf("BUILD ERROR: The release version number PCSCLITE_VERSION_NUMBER\n");
00227 printf(" in pcsclite.h (%s) does not match the release version number\n",
00228 PCSCLITE_VERSION_NUMBER);
00229 printf(" generated in config.h (%s) (see configure.in).\n", VERSION);
00230
00231 return EXIT_FAILURE;
00232 }
00233
00234
00235
00236
00237
00238 DebugLogSetLogType(DEBUGLOG_SYSLOG_DEBUG);
00239
00240
00241
00242
00243 #ifdef HAVE_GETOPT_LONG
00244 while ((opt = getopt_long (argc, argv, "c:fdhvaeC", long_options, &option_index)) != -1) {
00245 #else
00246 while ((opt = getopt (argc, argv, "c:fdhvaeC")) != -1) {
00247 #endif
00248 switch (opt) {
00249 case 'c':
00250 Log2(PCSC_LOG_INFO, "using new config file: %s", optarg);
00251 newReaderConfig = optarg;
00252 break;
00253
00254 case 'f':
00255 setToForeground = TRUE;
00256
00257 DebugLogSetLogType(DEBUGLOG_STDERR_DEBUG);
00258 Log1(PCSC_LOG_INFO,
00259 "pcscd set to foreground with debug send to stderr");
00260 break;
00261
00262 case 'd':
00263 DebugLogSetLevel(PCSC_LOG_DEBUG);
00264 break;
00265
00266 case 'e':
00267 DebugLogSetLevel(PCSC_LOG_ERROR);
00268 break;
00269
00270 case 'C':
00271 DebugLogSetLevel(PCSC_LOG_CRITICAL);
00272 break;
00273
00274 case 'h':
00275 print_usage (argv[0]);
00276 return EXIT_SUCCESS;
00277
00278 case 'v':
00279 print_version ();
00280 return EXIT_SUCCESS;
00281
00282 case 'a':
00283 DebugLogSetCategory(DEBUG_CATEGORY_APDU);
00284 break;
00285
00286 default:
00287 print_usage (argv[0]);
00288 return EXIT_FAILURE;
00289 }
00290
00291 }
00292
00293 if (argv[optind])
00294 {
00295 printf("Unknown option: %s\n\n", argv[optind]);
00296 print_usage(argv[0]);
00297 return EXIT_SUCCESS;
00298 }
00299
00300
00301
00302
00303
00304 rv = SYS_Stat(PCSCLITE_PUBSHM_FILE, &fStatBuf);
00305
00306 if (rv == 0)
00307 {
00308 #ifdef USE_RUN_PID
00309
00310
00311
00312
00313 FILE *f;
00314
00315
00316
00317 #define PID_ASCII_SIZE 11
00318 char pid_ascii[PID_ASCII_SIZE];
00319 int pid;
00320
00321 if ((f = fopen(USE_RUN_PID, "rb")) != NULL)
00322 {
00323 fgets(pid_ascii, PID_ASCII_SIZE, f);
00324 fclose(f);
00325
00326 pid = atoi(pid_ascii);
00327
00328 if (kill(pid, 0) == 0)
00329 {
00330 Log1(PCSC_LOG_CRITICAL,
00331 "file " PCSCLITE_PUBSHM_FILE " already exists.");
00332 Log2(PCSC_LOG_CRITICAL,
00333 "Another pcscd (pid: %d) seems to be running.", pid);
00334 return EXIT_FAILURE;
00335 }
00336 else
00337
00338 clean_temp_files();
00339 }
00340 else
00341 {
00342 Log1(PCSC_LOG_CRITICAL,
00343 "file " PCSCLITE_PUBSHM_FILE " already exists.");
00344 Log1(PCSC_LOG_CRITICAL,
00345 "Maybe another pcscd is running?");
00346 Log1(PCSC_LOG_CRITICAL,
00347 "I can't read process pid from " USE_RUN_PID);
00348 Log1(PCSC_LOG_CRITICAL,
00349 "Remove " PCSCLITE_PUBSHM_FILE " and " PCSCLITE_CSOCK_NAME);
00350 Log1(PCSC_LOG_CRITICAL,
00351 "if pcscd is not running to clear this message.");
00352 return EXIT_FAILURE;
00353 }
00354 #else
00355 Log1(PCSC_LOG_CRITICAL,
00356 "file " PCSCLITE_PUBSHM_FILE " already exists.");
00357 Log1(PCSC_LOG_CRITICAL,
00358 "Maybe another pcscd is running?");
00359 Log1(PCSC_LOG_CRITICAL,
00360 "Remove " PCSCLITE_PUBSHM_FILE " and " PCSCLITE_CSOCK_NAME);
00361 Log1(PCSC_LOG_CRITICAL,
00362 "if pcscd is not running to clear this message.");
00363 return EXIT_FAILURE;
00364 #endif
00365 }
00366
00367
00368
00369
00370 if (!setToForeground)
00371 {
00372 if (SYS_Daemon(0, 0))
00373 Log2(PCSC_LOG_CRITICAL, "SYS_Daemon() failed: %s",
00374 strerror(errno));
00375 }
00376
00377
00378
00379
00380 signal(SIGQUIT, signal_trap);
00381 signal(SIGTERM, signal_trap);
00382 signal(SIGINT, signal_trap);
00383 signal(SIGHUP, signal_trap);
00384
00385 #ifdef USE_RUN_PID
00386
00387
00388
00389
00390 {
00391 FILE *f;
00392
00393 if ((f = fopen(USE_RUN_PID, "wb")) != NULL)
00394 {
00395 fprintf(f, "%u\n", (unsigned) getpid());
00396 fclose(f);
00397 }
00398 }
00399 #endif
00400
00401
00402
00403
00404 rv = SYS_Stat(PCSCLITE_IPC_DIR, &fStatBuf);
00405 if (rv < 0)
00406 {
00407 rv = SYS_Mkdir(PCSCLITE_IPC_DIR, S_ISVTX | S_IRWXO | S_IRWXG | S_IRWXU);
00408 if (rv != 0)
00409 {
00410 Log2(PCSC_LOG_CRITICAL,
00411 "cannot create " PCSCLITE_IPC_DIR ": %s", strerror(errno));
00412 return EXIT_FAILURE;
00413 }
00414 }
00415
00416
00417 if (atexit(at_exit))
00418 Log2(PCSC_LOG_CRITICAL, "atexit() failed: %s", strerror(errno));
00419
00420
00421
00422
00423 RFAllocateReaderSpace();
00424
00425
00426
00427
00428 if (newReaderConfig)
00429 {
00430 rv = RFStartSerialReaders(newReaderConfig);
00431 if (rv != 0)
00432 {
00433 Log3(PCSC_LOG_CRITICAL, "invalid file %s: %s", newReaderConfig,
00434 strerror(errno));
00435 at_exit();
00436 }
00437 }
00438 else
00439 {
00440 rv = RFStartSerialReaders(PCSCLITE_READER_CONFIG);
00441
00442 #if 0
00443 if (rv == 1)
00444 {
00445 Log1(PCSC_LOG_INFO,
00446 "warning: no " PCSCLITE_READER_CONFIG " found");
00447
00448
00449
00450 }
00451 else
00452 #endif
00453 if (rv == -1)
00454 at_exit();
00455 }
00456
00457
00458
00459
00460 g_rgSCardT0Pci.dwProtocol = SCARD_PROTOCOL_T0;
00461 g_rgSCardT1Pci.dwProtocol = SCARD_PROTOCOL_T1;
00462 g_rgSCardRawPci.dwProtocol = SCARD_PROTOCOL_RAW;
00463
00464 Log1(PCSC_LOG_INFO, "pcsc-lite " VERSION " daemon ready.");
00465
00466
00467
00468
00469 Init = FALSE;
00470
00471
00472
00473
00474 signal(SIGQUIT, signal_trap);
00475 signal(SIGTERM, signal_trap);
00476 signal(SIGINT, signal_trap);
00477 signal(SIGHUP, signal_trap);
00478
00479 signal(SIGUSR1, signal_reload);
00480
00481 SVCServiceRunLoop();
00482
00483 Log1(PCSC_LOG_ERROR, "SVCServiceRunLoop returned");
00484 return EXIT_FAILURE;
00485 }
00486
00487 void at_exit(void)
00488 {
00489 Log1(PCSC_LOG_INFO, "cleaning " PCSCLITE_IPC_DIR);
00490
00491 clean_temp_files();
00492
00493 SYS_Exit(EXIT_SUCCESS);
00494 }
00495
00496 void clean_temp_files(void)
00497 {
00498 int rv;
00499
00500 rv = SYS_Unlink(PCSCLITE_PUBSHM_FILE);
00501 if (rv != 0)
00502 Log2(PCSC_LOG_ERROR, "Cannot unlink " PCSCLITE_PUBSHM_FILE ": %s",
00503 strerror(errno));
00504
00505 rv = SYS_Unlink(PCSCLITE_CSOCK_NAME);
00506 if (rv != 0)
00507 Log2(PCSC_LOG_ERROR, "Cannot unlink " PCSCLITE_CSOCK_NAME ": %s",
00508 strerror(errno));
00509
00510 #ifdef USE_RUN_PID
00511 rv = SYS_Unlink(USE_RUN_PID);
00512 if (rv != 0)
00513 Log2(PCSC_LOG_ERROR, "Cannot unlink " USE_RUN_PID ": %s",
00514 strerror(errno));
00515 #endif
00516 }
00517
00518 void signal_reload(int sig)
00519 {
00520 Log1(PCSC_LOG_INFO, "Reload serial configuration");
00521 HPReCheckSerialReaders();
00522 }
00523
00524 void signal_trap(int sig)
00525 {
00526
00527 if (AraKiri == FALSE)
00528 {
00529 Log1(PCSC_LOG_INFO, "Preparing for suicide");
00530 AraKiri = TRUE;
00531
00532
00533
00534
00535 if (Init)
00536 {
00537 Log1(PCSC_LOG_INFO, "Suicide during init");
00538 at_exit();
00539 }
00540 }
00541 }
00542
00543 void print_version (void)
00544 {
00545 printf("%s version %s.\n", PACKAGE, VERSION);
00546 printf("Copyright (C) 1999-2002 by David Corcoran <corcoran@linuxnet.com>.\n");
00547 printf("Copyright (C) 2001-2005 by Ludovic Rousseau <ludovic.rousseau@free.fr>.\n");
00548 printf("Copyright (C) 2003-2004 by Damien Sauveron <sauveron@labri.fr>.\n");
00549 printf("Report bugs to <sclinux@linuxnet.com>.\n");
00550 }
00551
00552 void print_usage (char const * const progname)
00553 {
00554 printf("Usage: %s options\n", progname);
00555 printf("Options:\n");
00556 #ifdef HAVE_GETOPT_LONG
00557 printf(" -a, --apdu log APDU commands and results\n");
00558 printf(" -c, --config path to reader.conf\n");
00559 printf(" -f, --foreground run in foreground (no daemon),\n");
00560 printf(" send logs to stderr instead of syslog\n");
00561 printf(" -h, --help display usage information\n");
00562 printf(" -v, --version display the program version number\n");
00563 printf(" -d, --debug display lower level debug messages\n");
00564 printf(" --info display info level debug messages (default level)\n");
00565 printf(" -e --error display error level debug messages\n");
00566 printf(" -C --critical display critical only level debug messages\n");
00567 #else
00568 printf(" -a log APDU commands and results\n");
00569 printf(" -c path to reader.conf\n");
00570 printf(" -f run in foreground (no daemon), send logs to stderr instead of syslog\n");
00571 printf(" -d display debug messages. Output may be:\n");
00572 printf(" -h display usage information\n");
00573 printf(" -v display the program version number\n");
00574 #endif
00575 }
00576