pcsc-lite 1.5.5
|
00001 /* 00002 * MUSCLE SmartCard Development ( http://www.linuxnet.com ) 00003 * 00004 * Copyright (C) 1999-2002 00005 * David Corcoran <corcoran@linuxnet.com> 00006 * Copyright (C) 1999-2008 00007 * Ludovic Rousseau <ludovic.rousseau@free.fr> 00008 * 00009 * $Id: pcscdaemon.c 4298 2009-07-03 13:11:44Z rousseau $ 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 * Some internal functions 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; /* Connection ID used to reference the Client */ 00085 00086 rsp = 0; 00087 rv = 0; 00088 00089 /* 00090 * Initialize the comm structure 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 * Initialize the contexts structure 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 * Solaris sends a SIGALRM and it is annoying 00113 */ 00114 00115 (void)signal(SIGALRM, SIG_IGN); 00116 (void)signal(SIGPIPE, SIG_IGN); 00117 (void)signal(SIGHUP, SIG_IGN); /* needed for Solaris. The signal is sent 00118 * when the shell is existed */ 00119 00120 /* 00121 * This function always returns zero 00122 */ 00123 rsp = SYS_MutexInit(&usbNotifierMutex); 00124 00125 /* 00126 * Set up the search for USB/PCMCIA devices 00127 */ 00128 rsp = HPSearchHotPluggables(); 00129 if (rsp) 00130 return; 00131 00132 rsp = HPRegisterForHotplugEvents(); 00133 if (rsp) 00134 return; 00135 00136 /* 00137 * Set up the power management callback routine 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 * timeout in SHMProcessEventsServer(): do nothing 00157 * this is used to catch the Ctrl-C signal at some time when 00158 * nothing else happens 00159 */ 00160 break; 00161 00162 case -1: 00163 Log1(PCSC_LOG_ERROR, "Error in SHMProcessEventsServer"); 00164 break; 00165 00166 case -2: 00167 /* Nothing to do in case of a syscall interrupted 00168 * It happens when SIGUSR1 (reload) or SIGINT (Ctrl-C) is received 00169 * We just try again */ 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 /* stop the hotpug thread and waits its exit */ 00181 (void)HPStopHotPluggables(); 00182 (void)SYS_Sleep(1); 00183 00184 /* now stop all the drivers */ 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 * test the version 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 * By default we create a daemon (not connected to any output) 00237 * so log to syslog to have error messages. 00238 */ 00239 DebugLogSetLogType(DEBUGLOG_SYSLOG_DEBUG); 00240 00241 /* 00242 * Handle any command line arguments 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 /* debug to stderr instead of default syslog */ 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 /* debug to stderr instead of default syslog */ 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 * test the presence of /var/run/pcscd/pcsc.pub 00316 */ 00317 00318 rv = SYS_Stat(PCSCLITE_PUBSHM_FILE, &fStatBuf); 00319 00320 if (rv == 0) 00321 { 00322 pid_t pid; 00323 00324 /* read the pid file to get the old pid and test if the old pcscd is 00325 * still running 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 /* the old pcscd is dead. make some cleanup */ 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 * If this is set to one the user has asked it not to fork 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 * cleanly remove /var/run/pcscd/files when exiting 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 * If PCSCLITE_IPC_DIR does not exist then create it 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 /* set mode so that the directory is world readable and 00410 * executable even is umask is restrictive 00411 * The directory containes files used by libpcsclite */ 00412 (void)SYS_Chmod(PCSCLITE_IPC_DIR, mode); 00413 } 00414 00415 /* 00416 * Record our pid to make it easier 00417 * to kill the correct pcscd 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 /* set mode so that the file is world readable even is umask is 00432 * restrictive 00433 * The file is used by libpcsclite */ 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 * If PCSCLITE_EVENTS does not exist then create it 00443 */ 00444 rv = SYS_Stat(PCSCLITE_EVENTS_DIR, &fStatBuf); 00445 if (rv < 0) 00446 { 00447 /* 1733 : world writable + sticky bit */ 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 /* cleanly remove /var/run/pcscd/pcsc.* files when exiting */ 00461 if (atexit(at_exit)) 00462 Log2(PCSC_LOG_CRITICAL, "atexit() failed: %s", strerror(errno)); 00463 00464 /* 00465 * Allocate memory for reader structures 00466 */ 00467 (void)RFAllocateReaderSpace(); 00468 00469 /* 00470 * Grab the information from the reader.conf 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 * Token error in file 00494 */ 00495 } 00496 else 00497 #endif 00498 if (rv == -1) 00499 { 00500 ExitValue = EXIT_FAILURE; 00501 at_exit(); 00502 } 00503 } 00504 00505 /* 00506 * Set the default globals 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 * post initialistion 00516 */ 00517 Init = FALSE; 00518 00519 /* 00520 * signal_trap() does just set a global variable used by the main loop 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 SYS_Sleep(1); 00565 rv = SYS_RemoveFile(PCSCLITE_EVENTS_DIR); 00566 if (rv != 0) 00567 Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_EVENTS_DIR ": %s", 00568 strerror(errno)); 00569 } 00570 00571 static void signal_reload(/*@unused@*/ int sig) 00572 { 00573 (void)sig; 00574 00575 if (AraKiri) 00576 return; 00577 00578 HPReCheckSerialReaders(); 00579 } /* signal_reload */ 00580 00581 static void signal_trap(/*@unused@*/ int sig) 00582 { 00583 (void)sig; 00584 00585 /* the signal handler is called several times for the same Ctrl-C */ 00586 if (AraKiri == FALSE) 00587 { 00588 Log1(PCSC_LOG_INFO, "Preparing for suicide"); 00589 AraKiri = TRUE; 00590 00591 /* if still in the init/loading phase the AraKiri will not be 00592 * seen by the main event loop 00593 */ 00594 if (Init) 00595 { 00596 Log1(PCSC_LOG_INFO, "Suicide during init"); 00597 at_exit(); 00598 } 00599 } 00600 } 00601 00602 static void print_version (void) 00603 { 00604 printf("%s version %s.\n", PACKAGE, VERSION); 00605 printf("Copyright (C) 1999-2002 by David Corcoran <corcoran@linuxnet.com>.\n"); 00606 printf("Copyright (C) 2001-2008 by Ludovic Rousseau <ludovic.rousseau@free.fr>.\n"); 00607 printf("Copyright (C) 2003-2004 by Damien Sauveron <sauveron@labri.fr>.\n"); 00608 printf("Report bugs to <muscle@lists.musclecard.com>.\n"); 00609 00610 printf ("Enabled features:%s\n", PCSCLITE_FEATURES); 00611 } 00612 00613 static void print_usage (char const * const progname) 00614 { 00615 printf("Usage: %s options\n", progname); 00616 printf("Options:\n"); 00617 #ifdef HAVE_GETOPT_LONG 00618 printf(" -a, --apdu log APDU commands and results\n"); 00619 printf(" -c, --config path to reader.conf\n"); 00620 printf(" -f, --foreground run in foreground (no daemon),\n"); 00621 printf(" send logs to stderr instead of syslog\n"); 00622 printf(" -h, --help display usage information\n"); 00623 printf(" -H, --hotplug ask the daemon to rescan the available readers\n"); 00624 printf(" -v, --version display the program version number\n"); 00625 printf(" -d, --debug display lower level debug messages\n"); 00626 printf(" --info display info level debug messages (default level)\n"); 00627 printf(" -e --error display error level debug messages\n"); 00628 printf(" -C --critical display critical only level debug messages\n"); 00629 printf(" --force-reader-polling ignore the IFD_GENERATE_HOTPLUG reader capability\n"); 00630 #else 00631 printf(" -a log APDU commands and results\n"); 00632 printf(" -c path to reader.conf\n"); 00633 printf(" -f run in foreground (no daemon), send logs to stderr instead of syslog\n"); 00634 printf(" -d display debug messages. Output may be:\n"); 00635 printf(" -h display usage information\n"); 00636 printf(" -H ask the daemon to rescan the available readers\n"); 00637 printf(" -v display the program version number\n"); 00638 #endif 00639 } 00640