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 pid = fork();
00375 if (-1 == pid )
00376 Log2(PCSC_LOG_CRITICAL, "fork() failed: %s", strerror(errno));
00377
00378 if (pid)
00379
00380 return EXIT_SUCCESS;
00381 }
00382
00383
00384
00385
00386 if (!setToForeground)
00387 {
00388 int pid;
00389
00390 if (pipe(pipefd) == -1)
00391 {
00392 Log2(PCSC_LOG_CRITICAL, "pipe() failed: %s", strerror(errno));
00393 return EXIT_FAILURE;
00394 }
00395
00396 pid = fork();
00397 if (-1 == pid)
00398 {
00399 Log2(PCSC_LOG_CRITICAL, "fork() failed: %s", strerror(errno));
00400 return EXIT_FAILURE;
00401 }
00402
00403
00404
00405 (void)close(0);
00406 (void)close(1);
00407 (void)close(2);
00408
00409 if (pid)
00410
00411 {
00412 char buf;
00413 int ret;
00414
00415
00416 close(pipefd[1]);
00417
00418
00419 ret = read(pipefd[0], &buf, 1);
00420 if (ret <= 0)
00421 return 2;
00422
00423 close(pipefd[0]);
00424
00425
00426 return buf;
00427 }
00428 else
00429
00430 {
00431
00432 close(pipefd[0]);
00433 }
00434 }
00435
00436
00437
00438
00439
00440 (void)signal(SIGQUIT, signal_trap);
00441 (void)signal(SIGTERM, signal_trap);
00442 (void)signal(SIGINT, signal_trap);
00443
00444
00445 (void)signal(SIGALRM, signal_trap);
00446
00447
00448
00449
00450 rv = stat(PCSCLITE_IPC_DIR, &fStatBuf);
00451 if (rv < 0)
00452 {
00453 int mode = S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU;
00454
00455 rv = mkdir(PCSCLITE_IPC_DIR, mode);
00456 if (rv != 0)
00457 {
00458 Log2(PCSC_LOG_CRITICAL,
00459 "cannot create " PCSCLITE_IPC_DIR ": %s", strerror(errno));
00460 return EXIT_FAILURE;
00461 }
00462
00463
00464
00465
00466 (void)chmod(PCSCLITE_IPC_DIR, mode);
00467 }
00468
00469
00470
00471
00472
00473 {
00474 int f;
00475 int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
00476
00477 if ((f = open(PCSCLITE_RUN_PID, O_RDWR | O_CREAT, mode)) != -1)
00478 {
00479 char pid[PID_ASCII_SIZE];
00480
00481 (void)snprintf(pid, sizeof(pid), "%u\n", (unsigned) getpid());
00482 (void)write(f, pid, strlen(pid));
00483 (void)close(f);
00484
00485
00486
00487
00488 (void)chmod(PCSCLITE_RUN_PID, mode);
00489 }
00490 else
00491 Log2(PCSC_LOG_CRITICAL, "cannot create " PCSCLITE_RUN_PID ": %s",
00492 strerror(errno));
00493 }
00494
00495
00496 if (atexit(at_exit))
00497 Log2(PCSC_LOG_CRITICAL, "atexit() failed: %s", strerror(errno));
00498
00499
00500
00501
00502 rv = RFAllocateReaderSpace(customMaxReaderHandles);
00503 if (SCARD_S_SUCCESS != rv)
00504 at_exit();
00505
00506 #ifdef USE_SERIAL
00507
00508
00509
00510 if (newReaderConfig)
00511 {
00512 rv = RFStartSerialReaders(newReaderConfig);
00513 if (rv != 0)
00514 {
00515 Log3(PCSC_LOG_CRITICAL, "invalid file %s: %s", newReaderConfig,
00516 strerror(errno));
00517 at_exit();
00518 }
00519 }
00520 else
00521 {
00522 rv = RFStartSerialReaders(PCSCLITE_CONFIG_DIR);
00523 if (rv == -1)
00524 at_exit();
00525 }
00526 #endif
00527
00528 Log1(PCSC_LOG_INFO, "pcsc-lite " VERSION " daemon ready.");
00529
00530
00531
00532
00533 Init = FALSE;
00534
00535
00536
00537
00538 (void)signal(SIGUSR1, signal_reload);
00539
00540
00541
00542
00543 rv = InitializeSocket();
00544 if (rv)
00545 {
00546 Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
00547 at_exit();
00548 }
00549
00550
00551
00552
00553 rv = ContextsInitialize(customMaxThreadCounter, customMaxThreadCardHandles);
00554
00555 if (rv == -1)
00556 {
00557 Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
00558 at_exit();
00559 }
00560
00561 (void)signal(SIGPIPE, SIG_IGN);
00562 (void)signal(SIGHUP, SIG_IGN);
00563
00564
00565 #if !defined(PCSCLITE_STATIC_DRIVER) && defined(USE_USB)
00566
00567
00568
00569 rv = HPSearchHotPluggables();
00570 if (rv)
00571 at_exit();
00572
00573 rv = HPRegisterForHotplugEvents();
00574 if (rv)
00575 at_exit();
00576 #endif
00577
00578
00579
00580
00581 (void)PMRegisterForPowerEvents();
00582
00583
00584 if (pipefd[1] >= 0)
00585 {
00586 char buf = 0;
00587
00588
00589 write(pipefd[1], &buf, 1);
00590 close(pipefd[1]);
00591 }
00592
00593 SVCServiceRunLoop();
00594
00595 Log1(PCSC_LOG_ERROR, "SVCServiceRunLoop returned");
00596 return EXIT_FAILURE;
00597 }
00598
00599 static void at_exit(void)
00600 {
00601 Log1(PCSC_LOG_INFO, "cleaning " PCSCLITE_IPC_DIR);
00602
00603 clean_temp_files();
00604
00605 if (pipefd[1] >= 0)
00606 {
00607 char buf;
00608
00609
00610 buf = ExitValue;
00611 write(pipefd[1], &buf, 1);
00612 close(pipefd[1]);
00613 }
00614
00615 _exit(ExitValue);
00616 }
00617
00618 static void clean_temp_files(void)
00619 {
00620 int rv;
00621
00622 rv = remove(PCSCLITE_CSOCK_NAME);
00623 if (rv != 0)
00624 Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_CSOCK_NAME ": %s",
00625 strerror(errno));
00626
00627 rv = remove(PCSCLITE_RUN_PID);
00628 if (rv != 0)
00629 Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_RUN_PID ": %s",
00630 strerror(errno));
00631 }
00632
00633 static void signal_reload( int sig)
00634 {
00635 (void)signal(SIGUSR1, signal_reload);
00636
00637 (void)sig;
00638
00639 if (AraKiri)
00640 return;
00641
00642 #ifdef USE_USB
00643 HPReCheckSerialReaders();
00644 #endif
00645 }
00646
00647 static void signal_trap(int sig)
00648 {
00649 Log2(PCSC_LOG_INFO, "Received signal: %d", sig);
00650
00651
00652 if (AraKiri == FALSE)
00653 {
00654 Log1(PCSC_LOG_INFO, "Preparing for suicide");
00655 AraKiri = TRUE;
00656
00657
00658
00659
00660 if (Init)
00661 {
00662 Log1(PCSC_LOG_INFO, "Suicide during init");
00663 at_exit();
00664 }
00665 }
00666 }
00667
00668 static void print_version (void)
00669 {
00670 printf("%s version %s.\n", PACKAGE, VERSION);
00671 printf("Copyright (C) 1999-2002 by David Corcoran <corcoran@linuxnet.com>.\n");
00672 printf("Copyright (C) 2001-2010 by Ludovic Rousseau <ludovic.rousseau@free.fr>.\n");
00673 printf("Copyright (C) 2003-2004 by Damien Sauveron <sauveron@labri.fr>.\n");
00674 printf("Report bugs to <muscle@lists.musclecard.com>.\n");
00675
00676 printf ("Enabled features:%s\n", PCSCLITE_FEATURES);
00677 }
00678
00679 static void print_usage (char const * const progname)
00680 {
00681 printf("Usage: %s options\n", progname);
00682 printf("Options:\n");
00683 #ifdef HAVE_GETOPT_LONG
00684 printf(" -a, --apdu log APDU commands and results\n");
00685 printf(" -c, --config path to reader.conf\n");
00686 printf(" -f, --foreground run in foreground (no daemon),\n");
00687 printf(" send logs to stderr instead of syslog\n");
00688 printf(" -h, --help display usage information\n");
00689 printf(" -H, --hotplug ask the daemon to rescan the available readers\n");
00690 printf(" -v, --version display the program version number\n");
00691 printf(" -d, --debug display lower level debug messages\n");
00692 printf(" --info display info level debug messages (default level)\n");
00693 printf(" -e --error display error level debug messages\n");
00694 printf(" -C --critical display critical only level debug messages\n");
00695 printf(" --force-reader-polling ignore the IFD_GENERATE_HOTPLUG reader capability\n");
00696 printf(" -t, --max-thread maximum number of threads (default %d)\n", PCSC_MAX_CONTEXT_THREADS);
00697 printf(" -s, --max-card-handle-per-thread maximum number of card handle per thread (default: %d)\n", PCSC_MAX_CONTEXT_CARD_HANDLES);
00698 printf(" -r, --max-card-handle-per-reader maximum number of card handle per reader (default: %d)\n", PCSC_MAX_READER_HANDLES);
00699 #else
00700 printf(" -a log APDU commands and results\n");
00701 printf(" -c path to reader.conf\n");
00702 printf(" -f run in foreground (no daemon), send logs to stderr instead of syslog\n");
00703 printf(" -d display debug messages. Output may be:\n");
00704 printf(" -h display usage information\n");
00705 printf(" -H ask the daemon to rescan the available readers\n");
00706 printf(" -v display the program version number\n");
00707 printf(" -t maximum number of threads\n");
00708 printf(" -s maximum number of card handle per thread\n");
00709 printf(" -r maximum number of card handle per reader\n");
00710 #endif
00711 }
00712