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 int mode = S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU;
00400
00401 rv = SYS_Mkdir(PCSCLITE_IPC_DIR, mode);
00402 if (rv != 0)
00403 {
00404 Log2(PCSC_LOG_CRITICAL,
00405 "cannot create " PCSCLITE_IPC_DIR ": %s", strerror(errno));
00406 return EXIT_FAILURE;
00407 }
00408
00409
00410
00411
00412 (void)SYS_Chmod(PCSCLITE_IPC_DIR, mode);
00413 }
00414
00415
00416
00417
00418
00419 {
00420 int f;
00421 int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
00422
00423 if ((f = SYS_OpenFile(PCSCLITE_RUN_PID, O_RDWR | O_CREAT, mode)) != -1)
00424 {
00425 char pid[PID_ASCII_SIZE];
00426
00427 (void)snprintf(pid, sizeof(pid), "%u\n", (unsigned) getpid());
00428 (void)SYS_WriteFile(f, pid, strlen(pid));
00429 (void)SYS_CloseFile(f);
00430
00431
00432
00433
00434 (void)SYS_Chmod(PCSCLITE_RUN_PID, mode);
00435 }
00436 else
00437 Log2(PCSC_LOG_CRITICAL, "cannot create " PCSCLITE_RUN_PID ": %s",
00438 strerror(errno));
00439 }
00440
00441
00442
00443
00444 rv = SYS_Stat(PCSCLITE_EVENTS_DIR, &fStatBuf);
00445 if (rv < 0)
00446 {
00447
00448 int mode = S_IRWXU | S_IWGRP | S_IXGRP | S_IWOTH | S_IXOTH | S_ISVTX;
00449
00450 rv = SYS_Mkdir(PCSCLITE_EVENTS_DIR, mode);
00451 if (rv != 0)
00452 {
00453 Log2(PCSC_LOG_CRITICAL,
00454 "cannot create " PCSCLITE_EVENTS_DIR ": %s", strerror(errno));
00455 return EXIT_FAILURE;
00456 }
00457 (void)SYS_Chmod(PCSCLITE_EVENTS_DIR, mode);
00458 }
00459
00460
00461 if (atexit(at_exit))
00462 Log2(PCSC_LOG_CRITICAL, "atexit() failed: %s", strerror(errno));
00463
00464
00465
00466
00467 (void)RFAllocateReaderSpace();
00468
00469
00470
00471
00472 if (newReaderConfig)
00473 {
00474 rv = RFStartSerialReaders(newReaderConfig);
00475 if (rv != 0)
00476 {
00477 Log3(PCSC_LOG_CRITICAL, "invalid file %s: %s", newReaderConfig,
00478 strerror(errno));
00479 ExitValue = EXIT_FAILURE;
00480 at_exit();
00481 }
00482 }
00483 else
00484 {
00485 rv = RFStartSerialReaders(PCSCLITE_READER_CONFIG);
00486
00487 #if 0
00488 if (rv == 1)
00489 {
00490 Log1(PCSC_LOG_INFO,
00491 "warning: no " PCSCLITE_READER_CONFIG " found");
00492
00493
00494
00495 }
00496 else
00497 #endif
00498 if (rv == -1)
00499 {
00500 ExitValue = EXIT_FAILURE;
00501 at_exit();
00502 }
00503 }
00504
00505
00506
00507
00508 g_rgSCardT0Pci.dwProtocol = SCARD_PROTOCOL_T0;
00509 g_rgSCardT1Pci.dwProtocol = SCARD_PROTOCOL_T1;
00510 g_rgSCardRawPci.dwProtocol = SCARD_PROTOCOL_RAW;
00511
00512 Log1(PCSC_LOG_INFO, "pcsc-lite " VERSION " daemon ready.");
00513
00514
00515
00516
00517 Init = FALSE;
00518
00519
00520
00521
00522 (void)signal(SIGQUIT, signal_trap);
00523 (void)signal(SIGTERM, signal_trap);
00524 (void)signal(SIGINT, signal_trap);
00525 (void)signal(SIGHUP, signal_trap);
00526
00527 (void)signal(SIGUSR1, signal_reload);
00528
00529 SVCServiceRunLoop();
00530
00531 Log1(PCSC_LOG_ERROR, "SVCServiceRunLoop returned");
00532 return EXIT_FAILURE;
00533 }
00534
00535 static void at_exit(void)
00536 {
00537 Log1(PCSC_LOG_INFO, "cleaning " PCSCLITE_IPC_DIR);
00538
00539 clean_temp_files();
00540
00541 SYS_Exit(ExitValue);
00542 }
00543
00544 static void clean_temp_files(void)
00545 {
00546 int rv;
00547
00548 rv = SYS_RemoveFile(PCSCLITE_PUBSHM_FILE);
00549 if (rv != 0)
00550 Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_PUBSHM_FILE ": %s",
00551 strerror(errno));
00552
00553 rv = SYS_RemoveFile(PCSCLITE_CSOCK_NAME);
00554 if (rv != 0)
00555 Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_CSOCK_NAME ": %s",
00556 strerror(errno));
00557
00558 rv = SYS_RemoveFile(PCSCLITE_RUN_PID);
00559 if (rv != 0)
00560 Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_RUN_PID ": %s",
00561 strerror(errno));
00562
00563 (void)StatSynchronize(NULL);
00564 rv = SYS_RemoveFile(PCSCLITE_EVENTS_DIR);
00565 if (rv != 0)
00566 Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_EVENTS_DIR ": %s",
00567 strerror(errno));
00568 }
00569
00570 static void signal_reload( int sig)
00571 {
00572 (void)sig;
00573
00574 if (AraKiri)
00575 return;
00576
00577 HPReCheckSerialReaders();
00578 }
00579
00580 static void signal_trap( int sig)
00581 {
00582 (void)sig;
00583
00584
00585 if (AraKiri == FALSE)
00586 {
00587 Log1(PCSC_LOG_INFO, "Preparing for suicide");
00588 AraKiri = TRUE;
00589
00590
00591
00592
00593 if (Init)
00594 {
00595 Log1(PCSC_LOG_INFO, "Suicide during init");
00596 at_exit();
00597 }
00598 }
00599 }
00600
00601 static void print_version (void)
00602 {
00603 printf("%s version %s.\n", PACKAGE, VERSION);
00604 printf("Copyright (C) 1999-2002 by David Corcoran <corcoran@linuxnet.com>.\n");
00605 printf("Copyright (C) 2001-2008 by Ludovic Rousseau <ludovic.rousseau@free.fr>.\n");
00606 printf("Copyright (C) 2003-2004 by Damien Sauveron <sauveron@labri.fr>.\n");
00607 printf("Report bugs to <muscle@lists.musclecard.com>.\n");
00608
00609 printf ("Enabled features:%s\n", PCSCLITE_FEATURES);
00610 }
00611
00612 static void print_usage (char const * const progname)
00613 {
00614 printf("Usage: %s options\n", progname);
00615 printf("Options:\n");
00616 #ifdef HAVE_GETOPT_LONG
00617 printf(" -a, --apdu log APDU commands and results\n");
00618 printf(" -c, --config path to reader.conf\n");
00619 printf(" -f, --foreground run in foreground (no daemon),\n");
00620 printf(" send logs to stderr instead of syslog\n");
00621 printf(" -h, --help display usage information\n");
00622 printf(" -H, --hotplug ask the daemon to rescan the available readers\n");
00623 printf(" -v, --version display the program version number\n");
00624 printf(" -d, --debug display lower level debug messages\n");
00625 printf(" --info display info level debug messages (default level)\n");
00626 printf(" -e --error display error level debug messages\n");
00627 printf(" -C --critical display critical only level debug messages\n");
00628 printf(" --force-reader-polling ignore the IFD_GENERATE_HOTPLUG reader capability\n");
00629 #else
00630 printf(" -a log APDU commands and results\n");
00631 printf(" -c path to reader.conf\n");
00632 printf(" -f run in foreground (no daemon), send logs to stderr instead of syslog\n");
00633 printf(" -d display debug messages. Output may be:\n");
00634 printf(" -h display usage information\n");
00635 printf(" -H ask the daemon to rescan the available readers\n");
00636 printf(" -v display the program version number\n");
00637 #endif
00638 }
00639