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