00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00021 #include "config.h"
00022 #include <time.h>
00023 #include <signal.h>
00024 #include <sys/types.h>
00025 #include <sys/stat.h>
00026 #include <fcntl.h>
00027 #include <errno.h>
00028 #include <stdio.h>
00029 #include <unistd.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032 #ifdef HAVE_GETOPT_H
00033 #include <getopt.h>
00034 #endif
00035
00036 #include "misc.h"
00037 #include "pcsclite.h"
00038 #include "pcscd.h"
00039 #include "debuglog.h"
00040 #include "winscard_msg.h"
00041 #include "winscard_svc.h"
00042 #include "sys_generic.h"
00043 #include "hotplug.h"
00044 #include "readerfactory.h"
00045 #include "configfile.h"
00046 #include "powermgt_generic.h"
00047 #include "utils.h"
00048
00049 #ifndef TRUE
00050 #define TRUE 1
00051 #define FALSE 0
00052 #endif
00053
00054 char AraKiri = FALSE;
00055 static char Init = TRUE;
00056 char AutoExit = FALSE;
00057 static int ExitValue = EXIT_FAILURE;
00058 int HPForceReaderPolling = 0;
00059 static int pipefd[] = {-1, -1};
00060
00061
00062
00063
00064 static void at_exit(void);
00065 static void clean_temp_files(void);
00066 static void signal_reload(int sig);
00067 static void signal_trap(int);
00068 static void print_version (void);
00069 static void print_usage (char const * const);
00070
00079 static void SVCServiceRunLoop(void)
00080 {
00081 int rsp;
00082 LONG rv;
00083 uint32_t dwClientID;
00084
00085 rv = 0;
00086
00087 while (TRUE)
00088 {
00089 switch (rsp = ProcessEventsServer(&dwClientID))
00090 {
00091
00092 case 0:
00093 Log2(PCSC_LOG_DEBUG, "A new context thread creation is requested: %d", dwClientID);
00094 rv = CreateContextThread(&dwClientID);
00095
00096 if (rv != SCARD_S_SUCCESS)
00097 Log1(PCSC_LOG_ERROR, "Problem during the context thread creation");
00098 break;
00099
00100 case 2:
00101
00102
00103
00104
00105
00106 break;
00107
00108 case -1:
00109 Log1(PCSC_LOG_ERROR, "Error in ProcessEventsServer");
00110 break;
00111
00112 case -2:
00113
00114
00115
00116 break;
00117
00118 default:
00119 Log2(PCSC_LOG_ERROR, "ProcessEventsServer unknown retval: %d",
00120 rsp);
00121 break;
00122 }
00123
00124 if (AraKiri)
00125 {
00126
00127 #ifdef USE_USB
00128 (void)HPStopHotPluggables();
00129 #endif
00130 (void)SYS_Sleep(1);
00131
00132
00133 RFCleanupReaders();
00134 ContextsDeinitialize();
00135 at_exit();
00136 }
00137 }
00138 }
00139
00140 int main(int argc, char **argv)
00141 {
00142 int rv;
00143 char setToForeground;
00144 char HotPlug;
00145 char *newReaderConfig;
00146 struct stat fStatBuf;
00147 int customMaxThreadCounter = 0;
00148 int customMaxReaderHandles = 0;
00149 int customMaxThreadCardHandles = 0;
00150 int opt;
00151 #ifdef HAVE_GETOPT_LONG
00152 int option_index = 0;
00153 static struct option long_options[] = {
00154 {"config", 1, NULL, 'c'},
00155 {"foreground", 0, NULL, 'f'},
00156 {"help", 0, NULL, 'h'},
00157 {"version", 0, NULL, 'v'},
00158 {"apdu", 0, NULL, 'a'},
00159 {"debug", 0, NULL, 'd'},
00160 {"info", 0, NULL, 0},
00161 {"error", 0, NULL, 'e'},
00162 {"critical", 0, NULL, 'C'},
00163 {"hotplug", 0, NULL, 'H'},
00164 {"force-reader-polling", optional_argument, NULL, 0},
00165 {"max-thread", 1, NULL, 't'},
00166 {"max-card-handle-per-thread", 1, NULL, 's'},
00167 {"max-card-handle-per-reader", 1, NULL, 'r'},
00168 {"auto-exit", 0, NULL, 'x'},
00169 {NULL, 0, NULL, 0}
00170 };
00171 #endif
00172 #define OPT_STRING "c:fdhvaeCHt:r:s:x"
00173
00174 rv = 0;
00175 newReaderConfig = NULL;
00176 setToForeground = FALSE;
00177 HotPlug = FALSE;
00178
00179
00180
00181
00182 if (strcmp(PCSCLITE_VERSION_NUMBER, VERSION) != 0)
00183 {
00184 printf("BUILD ERROR: The release version number PCSCLITE_VERSION_NUMBER\n");
00185 printf(" in pcsclite.h (%s) does not match the release version number\n",
00186 PCSCLITE_VERSION_NUMBER);
00187 printf(" generated in config.h (%s) (see configure.in).\n", VERSION);
00188
00189 return EXIT_FAILURE;
00190 }
00191
00192
00193
00194
00195
00196 DebugLogSetLogType(DEBUGLOG_SYSLOG_DEBUG);
00197
00198
00199
00200
00201 #ifdef HAVE_GETOPT_LONG
00202 while ((opt = getopt_long (argc, argv, OPT_STRING, long_options, &option_index)) != -1) {
00203 #else
00204 while ((opt = getopt (argc, argv, OPT_STRING)) != -1) {
00205 #endif
00206 switch (opt) {
00207 #ifdef HAVE_GETOPT_LONG
00208 case 0:
00209 if (strcmp(long_options[option_index].name,
00210 "force-reader-polling") == 0)
00211 HPForceReaderPolling = optarg ? abs(atoi(optarg)) : 1;
00212 break;
00213 #endif
00214 case 'c':
00215 Log2(PCSC_LOG_INFO, "using new config file: %s", optarg);
00216 newReaderConfig = optarg;
00217 break;
00218
00219 case 'f':
00220 setToForeground = TRUE;
00221
00222 DebugLogSetLogType(DEBUGLOG_STDERR_DEBUG);
00223 Log1(PCSC_LOG_INFO,
00224 "pcscd set to foreground with debug send to stderr");
00225 break;
00226
00227 case 'd':
00228 DebugLogSetLevel(PCSC_LOG_DEBUG);
00229 break;
00230
00231 case 'e':
00232 DebugLogSetLevel(PCSC_LOG_ERROR);
00233 break;
00234
00235 case 'C':
00236 DebugLogSetLevel(PCSC_LOG_CRITICAL);
00237 break;
00238
00239 case 'h':
00240 print_usage (argv[0]);
00241 return EXIT_SUCCESS;
00242
00243 case 'v':
00244 print_version ();
00245 return EXIT_SUCCESS;
00246
00247 case 'a':
00248 (void)DebugLogSetCategory(DEBUG_CATEGORY_APDU);
00249 break;
00250
00251 case 'H':
00252
00253 DebugLogSetLogType(DEBUGLOG_STDERR_DEBUG);
00254 HotPlug = TRUE;
00255 break;
00256
00257 case 't':
00258 customMaxThreadCounter = optarg ? atoi(optarg) : 0;
00259 Log2(PCSC_LOG_INFO, "setting customMaxThreadCounter to: %d",
00260 customMaxThreadCounter);
00261 break;
00262
00263 case 'r':
00264 customMaxReaderHandles = optarg ? atoi(optarg) : 0;
00265 Log2(PCSC_LOG_INFO, "setting customMaxReaderHandles to: %d",
00266 customMaxReaderHandles);
00267 break;
00268
00269 case 's':
00270 customMaxThreadCardHandles = optarg ? atoi(optarg) : 0;
00271 Log2(PCSC_LOG_INFO, "setting customMaxThreadCardHandles to: %d",
00272 customMaxThreadCardHandles);
00273 break;
00274
00275 case 'x':
00276 AutoExit = TRUE;
00277 Log2(PCSC_LOG_INFO, "Auto exit after %d seconds of inactivity",
00278 TIME_BEFORE_SUICIDE);
00279 break;
00280
00281 default:
00282 print_usage (argv[0]);
00283 return EXIT_FAILURE;
00284 }
00285
00286 }
00287
00288 if (argv[optind])
00289 {
00290 printf("Unknown option: %s\n", argv[optind]);
00291 print_usage(argv[0]);
00292 return EXIT_FAILURE;
00293 }
00294
00295
00296
00297
00298
00299 rv = stat(PCSCLITE_CSOCK_NAME, &fStatBuf);
00300
00301 if (rv == 0)
00302 {
00303 pid_t pid;
00304
00305
00306
00307
00308 pid = GetDaemonPid();
00309
00310 if (pid != -1)
00311 {
00312 if (HotPlug)
00313 return SendHotplugSignal();
00314
00315 rv = kill(pid, 0);
00316 if (0 == rv)
00317 {
00318 Log1(PCSC_LOG_CRITICAL,
00319 "file " PCSCLITE_CSOCK_NAME " already exists.");
00320 Log2(PCSC_LOG_CRITICAL,
00321 "Another pcscd (pid: %d) seems to be running.", pid);
00322 return EXIT_FAILURE;
00323 }
00324 else
00325 if (ESRCH == errno)
00326 {
00327
00328 clean_temp_files();
00329 }
00330 else
00331 {
00332
00333 Log2(PCSC_LOG_CRITICAL, "kill failed: %s", strerror(errno));
00334 return EXIT_FAILURE;
00335 }
00336 }
00337 else
00338 {
00339 if (HotPlug)
00340 {
00341 Log1(PCSC_LOG_CRITICAL, "file " PCSCLITE_RUN_PID " do not exist");
00342 Log1(PCSC_LOG_CRITICAL, "Hotplug failed");
00343 return EXIT_FAILURE;
00344 }
00345
00346 Log1(PCSC_LOG_CRITICAL,
00347 "file " PCSCLITE_CSOCK_NAME " already exists.");
00348 Log1(PCSC_LOG_CRITICAL,
00349 "Maybe another pcscd is running?");
00350 Log1(PCSC_LOG_CRITICAL,
00351 "I can't read process pid from " PCSCLITE_RUN_PID);
00352 Log1(PCSC_LOG_CRITICAL, "Remove " PCSCLITE_CSOCK_NAME);
00353 Log1(PCSC_LOG_CRITICAL,
00354 "if pcscd is not running to clear this message.");
00355 return EXIT_FAILURE;
00356 }
00357 }
00358 else
00359 if (HotPlug)
00360 {
00361 Log1(PCSC_LOG_CRITICAL, "Hotplug failed: pcscd is not running");
00362 return EXIT_FAILURE;
00363 }
00364
00365
00366
00367 (void)chdir("/");
00368
00369 if (AutoExit)
00370 {
00371 int pid;
00372
00373
00374
00375 setsid();
00376
00377
00378 pid = fork();
00379 if (-1 == pid )
00380 Log2(PCSC_LOG_CRITICAL, "fork() failed: %s", strerror(errno));
00381
00382 if (pid)
00383
00384 return EXIT_SUCCESS;
00385 }
00386
00387
00388
00389
00390 if (!setToForeground)
00391 {
00392 int pid;
00393
00394 if (pipe(pipefd) == -1)
00395 {
00396 Log2(PCSC_LOG_CRITICAL, "pipe() failed: %s", strerror(errno));
00397 return EXIT_FAILURE;
00398 }
00399
00400 pid = fork();
00401 if (-1 == pid)
00402 {
00403 Log2(PCSC_LOG_CRITICAL, "fork() failed: %s", strerror(errno));
00404 return EXIT_FAILURE;
00405 }
00406
00407
00408
00409 (void)close(0);
00410 (void)close(1);
00411 (void)close(2);
00412
00413 if (pid)
00414
00415 {
00416 char buf;
00417 int ret;
00418
00419
00420 close(pipefd[1]);
00421
00422
00423 ret = read(pipefd[0], &buf, 1);
00424 if (ret <= 0)
00425 return 2;
00426
00427 close(pipefd[0]);
00428
00429
00430 return buf;
00431 }
00432 else
00433
00434 {
00435
00436 close(pipefd[0]);
00437 }
00438 }
00439
00440
00441
00442
00443
00444 (void)signal(SIGQUIT, signal_trap);
00445 (void)signal(SIGTERM, signal_trap);
00446 (void)signal(SIGINT, signal_trap);
00447
00448
00449 (void)signal(SIGALRM, signal_trap);
00450
00451
00452
00453
00454 rv = stat(PCSCLITE_IPC_DIR, &fStatBuf);
00455 if (rv < 0)
00456 {
00457 int mode = S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU;
00458
00459 rv = mkdir(PCSCLITE_IPC_DIR, mode);
00460 if (rv != 0)
00461 {
00462 Log2(PCSC_LOG_CRITICAL,
00463 "cannot create " PCSCLITE_IPC_DIR ": %s", strerror(errno));
00464 return EXIT_FAILURE;
00465 }
00466
00467
00468
00469
00470 (void)chmod(PCSCLITE_IPC_DIR, mode);
00471 }
00472
00473
00474
00475
00476
00477 {
00478 int f;
00479 int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
00480
00481 f = open(PCSCLITE_RUN_PID, O_RDWR | O_CREAT, mode);
00482 if (f != -1)
00483 {
00484 char pid[PID_ASCII_SIZE];
00485
00486 (void)snprintf(pid, sizeof(pid), "%u\n", (unsigned) getpid());
00487 (void)write(f, pid, strlen(pid));
00488 (void)close(f);
00489
00490
00491
00492
00493 (void)chmod(PCSCLITE_RUN_PID, mode);
00494 }
00495 else
00496 Log2(PCSC_LOG_CRITICAL, "cannot create " PCSCLITE_RUN_PID ": %s",
00497 strerror(errno));
00498 }
00499
00500
00501 if (atexit(at_exit))
00502 Log2(PCSC_LOG_CRITICAL, "atexit() failed: %s", strerror(errno));
00503
00504
00505
00506
00507 rv = RFAllocateReaderSpace(customMaxReaderHandles);
00508 if (SCARD_S_SUCCESS != rv)
00509 at_exit();
00510
00511 #ifdef USE_SERIAL
00512
00513
00514
00515 if (newReaderConfig)
00516 {
00517 rv = RFStartSerialReaders(newReaderConfig);
00518 if (rv != 0)
00519 {
00520 Log3(PCSC_LOG_CRITICAL, "invalid file %s: %s", newReaderConfig,
00521 strerror(errno));
00522 at_exit();
00523 }
00524 }
00525 else
00526 {
00527 rv = RFStartSerialReaders(PCSCLITE_CONFIG_DIR);
00528 if (rv == -1)
00529 at_exit();
00530 }
00531 #endif
00532
00533 Log1(PCSC_LOG_INFO, "pcsc-lite " VERSION " daemon ready.");
00534
00535
00536
00537
00538 Init = FALSE;
00539
00540
00541
00542
00543 (void)signal(SIGUSR1, signal_reload);
00544
00545
00546
00547
00548 rv = InitializeSocket();
00549 if (rv)
00550 {
00551 Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
00552 at_exit();
00553 }
00554
00555
00556
00557
00558 rv = ContextsInitialize(customMaxThreadCounter, customMaxThreadCardHandles);
00559
00560 if (rv == -1)
00561 {
00562 Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
00563 at_exit();
00564 }
00565
00566 (void)signal(SIGPIPE, SIG_IGN);
00567 (void)signal(SIGHUP, SIG_IGN);
00568
00569
00570 #if !defined(PCSCLITE_STATIC_DRIVER) && defined(USE_USB)
00571
00572
00573
00574 rv = HPSearchHotPluggables();
00575 if (rv)
00576 at_exit();
00577
00578 rv = HPRegisterForHotplugEvents();
00579 if (rv)
00580 at_exit();
00581 #endif
00582
00583
00584
00585
00586 (void)PMRegisterForPowerEvents();
00587
00588
00589 if (pipefd[1] >= 0)
00590 {
00591 char buf = 0;
00592
00593
00594 write(pipefd[1], &buf, 1);
00595 close(pipefd[1]);
00596 }
00597
00598 SVCServiceRunLoop();
00599
00600 Log1(PCSC_LOG_ERROR, "SVCServiceRunLoop returned");
00601 return EXIT_FAILURE;
00602 }
00603
00604 static void at_exit(void)
00605 {
00606 Log1(PCSC_LOG_INFO, "cleaning " PCSCLITE_IPC_DIR);
00607
00608 clean_temp_files();
00609
00610 if (pipefd[1] >= 0)
00611 {
00612 char buf;
00613
00614
00615 buf = ExitValue;
00616 write(pipefd[1], &buf, 1);
00617 close(pipefd[1]);
00618 }
00619
00620 _exit(ExitValue);
00621 }
00622
00623 static void clean_temp_files(void)
00624 {
00625 int rv;
00626
00627 rv = remove(PCSCLITE_CSOCK_NAME);
00628 if (rv != 0)
00629 Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_CSOCK_NAME ": %s",
00630 strerror(errno));
00631
00632 rv = remove(PCSCLITE_RUN_PID);
00633 if (rv != 0)
00634 Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_RUN_PID ": %s",
00635 strerror(errno));
00636 }
00637
00638 static void signal_reload( int sig)
00639 {
00640 (void)signal(SIGUSR1, signal_reload);
00641
00642 (void)sig;
00643
00644 if (AraKiri)
00645 return;
00646
00647 #ifdef USE_USB
00648 HPReCheckSerialReaders();
00649 #endif
00650 }
00651
00652 static void signal_trap(int sig)
00653 {
00654 Log2(PCSC_LOG_INFO, "Received signal: %d", sig);
00655
00656
00657 if (AraKiri == FALSE)
00658 {
00659 Log1(PCSC_LOG_INFO, "Preparing for suicide");
00660 AraKiri = TRUE;
00661
00662
00663
00664
00665 if (Init)
00666 {
00667 Log1(PCSC_LOG_INFO, "Suicide during init");
00668 at_exit();
00669 }
00670 }
00671 else
00672 {
00673
00674 static int lives = 2;
00675
00676 lives--;
00677
00678 if (0 == lives)
00679 {
00680 Log1(PCSC_LOG_INFO, "Forced suicide");
00681 at_exit();
00682 }
00683 }
00684 }
00685
00686 static void print_version (void)
00687 {
00688 printf("%s version %s.\n", PACKAGE, VERSION);
00689 printf("Copyright (C) 1999-2002 by David Corcoran <corcoran@linuxnet.com>.\n");
00690 printf("Copyright (C) 2001-2010 by Ludovic Rousseau <ludovic.rousseau@free.fr>.\n");
00691 printf("Copyright (C) 2003-2004 by Damien Sauveron <sauveron@labri.fr>.\n");
00692 printf("Report bugs to <muscle@lists.musclecard.com>.\n");
00693
00694 printf ("Enabled features:%s\n", PCSCLITE_FEATURES);
00695 }
00696
00697 static void print_usage (char const * const progname)
00698 {
00699 printf("Usage: %s options\n", progname);
00700 printf("Options:\n");
00701 #ifdef HAVE_GETOPT_LONG
00702 printf(" -a, --apdu log APDU commands and results\n");
00703 printf(" -c, --config path to reader.conf\n");
00704 printf(" -f, --foreground run in foreground (no daemon),\n");
00705 printf(" send logs to stderr instead of syslog\n");
00706 printf(" -h, --help display usage information\n");
00707 printf(" -H, --hotplug ask the daemon to rescan the available readers\n");
00708 printf(" -v, --version display the program version number\n");
00709 printf(" -d, --debug display lower level debug messages\n");
00710 printf(" --info display info level debug messages (default level)\n");
00711 printf(" -e --error display error level debug messages\n");
00712 printf(" -C --critical display critical only level debug messages\n");
00713 printf(" --force-reader-polling ignore the IFD_GENERATE_HOTPLUG reader capability\n");
00714 printf(" -t, --max-thread maximum number of threads (default %d)\n", PCSC_MAX_CONTEXT_THREADS);
00715 printf(" -s, --max-card-handle-per-thread maximum number of card handle per thread (default: %d)\n", PCSC_MAX_CONTEXT_CARD_HANDLES);
00716 printf(" -r, --max-card-handle-per-reader maximum number of card handle per reader (default: %d)\n", PCSC_MAX_READER_HANDLES);
00717 #else
00718 printf(" -a log APDU commands and results\n");
00719 printf(" -c path to reader.conf\n");
00720 printf(" -f run in foreground (no daemon), send logs to stderr instead of syslog\n");
00721 printf(" -d display debug messages. Output may be:\n");
00722 printf(" -h display usage information\n");
00723 printf(" -H ask the daemon to rescan the available readers\n");
00724 printf(" -v display the program version number\n");
00725 printf(" -t maximum number of threads\n");
00726 printf(" -s maximum number of card handle per thread\n");
00727 printf(" -r maximum number of card handle per reader\n");
00728 #endif
00729 }
00730