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 "thread_generic.h"
00044 #include "hotplug.h"
00045 #include "readerfactory.h"
00046 #include "configfile.h"
00047 #include "powermgt_generic.h"
00048 #include "utils.h"
00049
00050 #ifndef TRUE
00051 #define TRUE 1
00052 #define FALSE 0
00053 #endif
00054
00055 char AraKiri = FALSE;
00056 static char Init = TRUE;
00057 static int ExitValue = EXIT_SUCCESS;
00058 int HPForceReaderPolling = 0;
00059
00060
00061
00062
00063 static void at_exit(void);
00064 static void clean_temp_files(void);
00065 static void signal_reload(int sig);
00066 static void signal_trap(int);
00067 static void print_version (void);
00068 static void print_usage (char const * const);
00069
00070 PCSCLITE_MUTEX usbNotifierMutex;
00071
00080 static void SVCServiceRunLoop(void)
00081 {
00082 int rsp;
00083 LONG rv;
00084 uint32_t dwClientID;
00085
00086 rsp = 0;
00087 rv = 0;
00088
00089
00090
00091
00092 rsp = SHMInitializeCommonSegment();
00093
00094 if (rsp == -1)
00095 {
00096 Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
00097 exit(-1);
00098 }
00099
00100
00101
00102
00103 rv = ContextsInitialize();
00104
00105 if (rv == -1)
00106 {
00107 Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
00108 exit(-1);
00109 }
00110
00111
00112
00113
00114
00115 (void)signal(SIGALRM, SIG_IGN);
00116 (void)signal(SIGPIPE, SIG_IGN);
00117 (void)signal(SIGHUP, SIG_IGN);
00118
00119
00120
00121
00122
00123 rsp = SYS_MutexInit(&usbNotifierMutex);
00124
00125
00126
00127
00128 rsp = HPSearchHotPluggables();
00129 if (rsp)
00130 return;
00131
00132 rsp = HPRegisterForHotplugEvents();
00133 if (rsp)
00134 return;
00135
00136
00137
00138
00139 (void)PMRegisterForPowerEvents();
00140
00141 while (TRUE)
00142 {
00143 switch (rsp = SHMProcessEventsServer(&dwClientID))
00144 {
00145
00146 case 0:
00147 Log2(PCSC_LOG_DEBUG, "A new context thread creation is requested: %d", dwClientID);
00148 rv = CreateContextThread(&dwClientID);
00149
00150 if (rv != SCARD_S_SUCCESS)
00151 Log1(PCSC_LOG_ERROR, "Problem during the context thread creation");
00152 break;
00153
00154 case 2:
00155
00156
00157
00158
00159
00160 break;
00161
00162 case -1:
00163 Log1(PCSC_LOG_ERROR, "Error in SHMProcessEventsServer");
00164 break;
00165
00166 case -2:
00167
00168
00169
00170 break;
00171
00172 default:
00173 Log2(PCSC_LOG_ERROR, "SHMProcessEventsServer unknown retval: %d",
00174 rsp);
00175 break;
00176 }
00177
00178 if (AraKiri)
00179 {
00180
00181 (void)HPStopHotPluggables();
00182 (void)SYS_Sleep(1);
00183
00184
00185 RFCleanupReaders(1);
00186 }
00187 }
00188 }
00189
00190 int main(int argc, char **argv)
00191 {
00192 int rv;
00193 char setToForeground;
00194 char HotPlug;
00195 char *newReaderConfig;
00196 struct stat fStatBuf;
00197 int opt;
00198 #ifdef HAVE_GETOPT_LONG
00199 int option_index = 0;
00200 static struct option long_options[] = {
00201 {"config", 1, NULL, 'c'},
00202 {"foreground", 0, NULL, 'f'},
00203 {"help", 0, NULL, 'h'},
00204 {"version", 0, NULL, 'v'},
00205 {"apdu", 0, NULL, 'a'},
00206 {"debug", 0, NULL, 'd'},
00207 {"info", 0, NULL, 0},
00208 {"error", 0, NULL, 'e'},
00209 {"critical", 0, NULL, 'C'},
00210 {"hotplug", 0, NULL, 'H'},
00211 {"force-reader-polling", optional_argument, NULL, 0},
00212 {NULL, 0, NULL, 0}
00213 };
00214 #endif
00215 #define OPT_STRING "c:fdhvaeCH"
00216
00217 rv = 0;
00218 newReaderConfig = NULL;
00219 setToForeground = FALSE;
00220 HotPlug = FALSE;
00221
00222
00223
00224
00225 if (strcmp(PCSCLITE_VERSION_NUMBER, VERSION) != 0)
00226 {
00227 printf("BUILD ERROR: The release version number PCSCLITE_VERSION_NUMBER\n");
00228 printf(" in pcsclite.h (%s) does not match the release version number\n",
00229 PCSCLITE_VERSION_NUMBER);
00230 printf(" generated in config.h (%s) (see configure.in).\n", VERSION);
00231
00232 return EXIT_FAILURE;
00233 }
00234
00235
00236
00237
00238
00239 DebugLogSetLogType(DEBUGLOG_SYSLOG_DEBUG);
00240
00241
00242
00243
00244 #ifdef HAVE_GETOPT_LONG
00245 while ((opt = getopt_long (argc, argv, OPT_STRING, long_options, &option_index)) != -1) {
00246 #else
00247 while ((opt = getopt (argc, argv, OPT_STRING)) != -1) {
00248 #endif
00249 switch (opt) {
00250 #ifdef HAVE_GETOPT_LONG
00251 case 0:
00252 if (strcmp(long_options[option_index].name,
00253 "force-reader-polling") == 0)
00254 HPForceReaderPolling = optarg ? abs(atoi(optarg)) : 1;
00255 break;
00256 #endif
00257 case 'c':
00258 Log2(PCSC_LOG_INFO, "using new config file: %s", optarg);
00259 newReaderConfig = optarg;
00260 break;
00261
00262 case 'f':
00263 setToForeground = TRUE;
00264
00265 DebugLogSetLogType(DEBUGLOG_STDERR_DEBUG);
00266 Log1(PCSC_LOG_INFO,
00267 "pcscd set to foreground with debug send to stderr");
00268 break;
00269
00270 case 'd':
00271 DebugLogSetLevel(PCSC_LOG_DEBUG);
00272 break;
00273
00274 case 'e':
00275 DebugLogSetLevel(PCSC_LOG_ERROR);
00276 break;
00277
00278 case 'C':
00279 DebugLogSetLevel(PCSC_LOG_CRITICAL);
00280 break;
00281
00282 case 'h':
00283 print_usage (argv[0]);
00284 return EXIT_SUCCESS;
00285
00286 case 'v':
00287 print_version ();
00288 return EXIT_SUCCESS;
00289
00290 case 'a':
00291 (void)DebugLogSetCategory(DEBUG_CATEGORY_APDU);
00292 break;
00293
00294 case 'H':
00295
00296 DebugLogSetLogType(DEBUGLOG_STDERR_DEBUG);
00297 HotPlug = TRUE;
00298 break;
00299
00300 default:
00301 print_usage (argv[0]);
00302 return EXIT_FAILURE;
00303 }
00304
00305 }
00306
00307 if (argv[optind])
00308 {
00309 printf("Unknown option: %s\n\n", argv[optind]);
00310 print_usage(argv[0]);
00311 return EXIT_SUCCESS;
00312 }
00313
00314
00315
00316
00317
00318 rv = SYS_Stat(PCSCLITE_PUBSHM_FILE, &fStatBuf);
00319
00320 if (rv == 0)
00321 {
00322 pid_t pid;
00323
00324
00325
00326
00327 pid = GetDaemonPid();
00328
00329 if (pid != -1)
00330 {
00331 if (HotPlug)
00332 return SendHotplugSignal();
00333
00334 if (kill(pid, 0) == 0)
00335 {
00336 Log1(PCSC_LOG_CRITICAL,
00337 "file " PCSCLITE_PUBSHM_FILE " already exists.");
00338 Log2(PCSC_LOG_CRITICAL,
00339 "Another pcscd (pid: %d) seems to be running.", pid);
00340 return EXIT_FAILURE;
00341 }
00342 else
00343
00344 clean_temp_files();
00345 }
00346 else
00347 {
00348 if (HotPlug)
00349 {
00350 Log1(PCSC_LOG_CRITICAL, "file " PCSCLITE_RUN_PID " do not exist");
00351 Log1(PCSC_LOG_CRITICAL, "Hotplug failed");
00352 return EXIT_FAILURE;
00353 }
00354
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 "I can't read process pid from " PCSCLITE_RUN_PID);
00361 Log1(PCSC_LOG_CRITICAL,
00362 "Remove " PCSCLITE_PUBSHM_FILE " and " PCSCLITE_CSOCK_NAME);
00363 Log1(PCSC_LOG_CRITICAL,
00364 "if pcscd is not running to clear this message.");
00365 return EXIT_FAILURE;
00366 }
00367 }
00368 else
00369 if (HotPlug)
00370 {
00371 Log1(PCSC_LOG_CRITICAL, "Hotplug failed: pcscd is not running");
00372 return EXIT_FAILURE;
00373 }
00374
00375
00376
00377
00378 if (!setToForeground)
00379 {
00380 if (SYS_Daemon(0, 0))
00381 Log2(PCSC_LOG_CRITICAL, "SYS_Daemon() failed: %s",
00382 strerror(errno));
00383 }
00384
00385
00386
00387
00388 (void)signal(SIGQUIT, signal_trap);
00389 (void)signal(SIGTERM, signal_trap);
00390 (void)signal(SIGINT, signal_trap);
00391 (void)signal(SIGHUP, signal_trap);
00392
00393
00394
00395
00396 rv = SYS_Stat(PCSCLITE_IPC_DIR, &fStatBuf);
00397 if (rv < 0)
00398 {
00399 rv = SYS_Mkdir(PCSCLITE_IPC_DIR,
00400 S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU);
00401 if (rv != 0)
00402 {
00403 Log2(PCSC_LOG_CRITICAL,
00404 "cannot create " PCSCLITE_IPC_DIR ": %s", strerror(errno));
00405 return EXIT_FAILURE;
00406 }
00407 }
00408
00409
00410
00411
00412
00413 {
00414 int f;
00415 int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
00416
00417 if ((f = SYS_OpenFile(PCSCLITE_RUN_PID, O_RDWR | O_CREAT, mode)) != -1)
00418 {
00419 char pid[PID_ASCII_SIZE];
00420
00421 (void)snprintf(pid, sizeof(pid), "%u\n", (unsigned) getpid());
00422 (void)SYS_WriteFile(f, pid, strlen(pid));
00423 (void)SYS_CloseFile(f);
00424
00425
00426
00427
00428 (void)SYS_Chmod(PCSCLITE_RUN_PID, mode);
00429 }
00430 else
00431 Log2(PCSC_LOG_CRITICAL, "cannot create " PCSCLITE_RUN_PID ": %s",
00432 strerror(errno));
00433 }
00434
00435
00436
00437
00438 rv = SYS_Stat(PCSCLITE_EVENTS_DIR, &fStatBuf);
00439 if (rv < 0)
00440 {
00441
00442 int mode = S_IRWXU | S_IWGRP | S_IXGRP | S_IWOTH | S_IXOTH | S_ISVTX;
00443
00444 rv = SYS_Mkdir(PCSCLITE_EVENTS_DIR, mode);
00445 if (rv != 0)
00446 {
00447 Log2(PCSC_LOG_CRITICAL,
00448 "cannot create " PCSCLITE_EVENTS_DIR ": %s", strerror(errno));
00449 return EXIT_FAILURE;
00450 }
00451 (void)SYS_Chmod(PCSCLITE_EVENTS_DIR, mode);
00452 }
00453
00454
00455 if (atexit(at_exit))
00456 Log2(PCSC_LOG_CRITICAL, "atexit() failed: %s", strerror(errno));
00457
00458
00459
00460
00461 (void)RFAllocateReaderSpace();
00462
00463
00464
00465
00466 if (newReaderConfig)
00467 {
00468 rv = RFStartSerialReaders(newReaderConfig);
00469 if (rv != 0)
00470 {
00471 Log3(PCSC_LOG_CRITICAL, "invalid file %s: %s", newReaderConfig,
00472 strerror(errno));
00473 ExitValue = EXIT_FAILURE;
00474 at_exit();
00475 }
00476 }
00477 else
00478 {
00479 rv = RFStartSerialReaders(PCSCLITE_READER_CONFIG);
00480
00481 #if 0
00482 if (rv == 1)
00483 {
00484 Log1(PCSC_LOG_INFO,
00485 "warning: no " PCSCLITE_READER_CONFIG " found");
00486
00487
00488
00489 }
00490 else
00491 #endif
00492 if (rv == -1)
00493 {
00494 ExitValue = EXIT_FAILURE;
00495 at_exit();
00496 }
00497 }
00498
00499
00500
00501
00502 g_rgSCardT0Pci.dwProtocol = SCARD_PROTOCOL_T0;
00503 g_rgSCardT1Pci.dwProtocol = SCARD_PROTOCOL_T1;
00504 g_rgSCardRawPci.dwProtocol = SCARD_PROTOCOL_RAW;
00505
00506 Log1(PCSC_LOG_INFO, "pcsc-lite " VERSION " daemon ready.");
00507
00508
00509
00510
00511 Init = FALSE;
00512
00513
00514
00515
00516 (void)signal(SIGQUIT, signal_trap);
00517 (void)signal(SIGTERM, signal_trap);
00518 (void)signal(SIGINT, signal_trap);
00519 (void)signal(SIGHUP, signal_trap);
00520
00521 (void)signal(SIGUSR1, signal_reload);
00522
00523 SVCServiceRunLoop();
00524
00525 Log1(PCSC_LOG_ERROR, "SVCServiceRunLoop returned");
00526 return EXIT_FAILURE;
00527 }
00528
00529 static void at_exit(void)
00530 {
00531 Log1(PCSC_LOG_INFO, "cleaning " PCSCLITE_IPC_DIR);
00532
00533 clean_temp_files();
00534
00535 SYS_Exit(ExitValue);
00536 }
00537
00538 static void clean_temp_files(void)
00539 {
00540 int rv;
00541
00542 rv = SYS_RemoveFile(PCSCLITE_PUBSHM_FILE);
00543 if (rv != 0)
00544 Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_PUBSHM_FILE ": %s",
00545 strerror(errno));
00546
00547 rv = SYS_RemoveFile(PCSCLITE_CSOCK_NAME);
00548 if (rv != 0)
00549 Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_CSOCK_NAME ": %s",
00550 strerror(errno));
00551
00552 rv = SYS_RemoveFile(PCSCLITE_RUN_PID);
00553 if (rv != 0)
00554 Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_RUN_PID ": %s",
00555 strerror(errno));
00556
00557 (void)StatSynchronize(NULL);
00558 rv = SYS_RemoveFile(PCSCLITE_EVENTS_DIR);
00559 if (rv != 0)
00560 Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_EVENTS_DIR ": %s",
00561 strerror(errno));
00562 }
00563
00564 static void signal_reload( int sig)
00565 {
00566 (void)sig;
00567
00568 if (AraKiri)
00569 return;
00570
00571 HPReCheckSerialReaders();
00572 }
00573
00574 static void signal_trap( int sig)
00575 {
00576 (void)sig;
00577
00578
00579 if (AraKiri == FALSE)
00580 {
00581 Log1(PCSC_LOG_INFO, "Preparing for suicide");
00582 AraKiri = TRUE;
00583
00584
00585
00586
00587 if (Init)
00588 {
00589 Log1(PCSC_LOG_INFO, "Suicide during init");
00590 at_exit();
00591 }
00592 }
00593 }
00594
00595 static void print_version (void)
00596 {
00597 printf("%s version %s.\n", PACKAGE, VERSION);
00598 printf("Copyright (C) 1999-2002 by David Corcoran <corcoran@linuxnet.com>.\n");
00599 printf("Copyright (C) 2001-2008 by Ludovic Rousseau <ludovic.rousseau@free.fr>.\n");
00600 printf("Copyright (C) 2003-2004 by Damien Sauveron <sauveron@labri.fr>.\n");
00601 printf("Report bugs to <muscle@lists.musclecard.com>.\n");
00602
00603 printf ("Enabled features:%s\n", PCSCLITE_FEATURES);
00604 }
00605
00606 static void print_usage (char const * const progname)
00607 {
00608 printf("Usage: %s options\n", progname);
00609 printf("Options:\n");
00610 #ifdef HAVE_GETOPT_LONG
00611 printf(" -a, --apdu log APDU commands and results\n");
00612 printf(" -c, --config path to reader.conf\n");
00613 printf(" -f, --foreground run in foreground (no daemon),\n");
00614 printf(" send logs to stderr instead of syslog\n");
00615 printf(" -h, --help display usage information\n");
00616 printf(" -H, --hotplug ask the daemon to rescan the available readers\n");
00617 printf(" -v, --version display the program version number\n");
00618 printf(" -d, --debug display lower level debug messages\n");
00619 printf(" --info display info level debug messages (default level)\n");
00620 printf(" -e --error display error level debug messages\n");
00621 printf(" -C --critical display critical only level debug messages\n");
00622 printf(" --force-reader-polling ignore the IFD_GENERATE_HOTPLUG reader capability\n");
00623 #else
00624 printf(" -a log APDU commands and results\n");
00625 printf(" -c path to reader.conf\n");
00626 printf(" -f run in foreground (no daemon), send logs to stderr instead of syslog\n");
00627 printf(" -d display debug messages. Output may be:\n");
00628 printf(" -h display usage information\n");
00629 printf(" -H ask the daemon to rescan the available readers\n");
00630 printf(" -v display the program version number\n");
00631 #endif
00632 }
00633