1/* 2 * Copyright (c) 2000-2007 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * pcscdaemon.c 26 * SmartCardServices 27 */ 28 29/* 30 * MUSCLE SmartCard Development ( http://www.linuxnet.com ) 31 * 32 * Copyright (C) 1999-2005 33 * David Corcoran <corcoran@linuxnet.com> 34 * Ludovic Rousseau <ludovic.rousseau@free.fr> 35 * 36 * $Id: pcscdaemon.c 123 2010-03-27 10:50:42Z ludovic.rousseau@gmail.com $ 37 */ 38 39/** 40 * @file 41 * @brief This is the main pcscd daemon. 42 * 43 * The function \c main() starts up the communication environment.\n 44 * Then an endless loop is calld to look for Client connections. For each 45 * Client connection a call to \c CreateContextThread() is done. 46 */ 47 48#include "config.h" 49#include <time.h> 50#include <syslog.h> 51#include <signal.h> 52#include <sys/types.h> 53#include <sys/stat.h> 54#include <sys/errno.h> 55#include <stdio.h> 56#include <unistd.h> 57#include <stdlib.h> 58#include <string.h> 59#ifdef HAVE_GETOPT_H 60#include <getopt.h> 61#endif 62 63#include "wintypes.h" 64#include "pcsclite.h" 65#include "debuglog.h" 66#include "winscard_msg.h" 67#include "winscard_svc.h" 68#include "sys_generic.h" 69#include "thread_generic.h" 70#include "hotplug.h" 71#include "readerfactory.h" 72#include "configfile.h" 73#include "powermgt_generic.h" 74 75#include <security_utilities/debugging.h> 76 77char AraKiri = 0; 78static char Init = 1; 79int HPForceReaderPolling = 0; 80 81char **globalArgv; 82 83/* 84 * Some internal functions 85 */ 86void SVCServiceRunLoop(void); 87void SVCClientCleanup(psharedSegmentMsg); 88void at_exit(void); 89void clean_temp_files(void); 90void signal_reload(int sig); 91void signal_trap(int); 92void print_version (void); 93void print_usage (char const * const); 94int ProcessHotplugRequest(); 95 96PCSCLITE_MUTEX usbNotifierMutex; 97 98#ifdef USE_RUN_PID 99pid_t GetDaemonPid(void); 100pid_t GetDaemonPid(void) 101{ 102 FILE *f; 103 pid_t pid; 104 105 /* pids are only 15 bits but 4294967296 106 * (32 bits in case of a new system use it) is on 10 bytes 107 */ 108 if ((f = fopen(USE_RUN_PID, "rb")) != NULL) 109 { 110#define PID_ASCII_SIZE 11 111 char pid_ascii[PID_ASCII_SIZE]; 112 113 fgets(pid_ascii, PID_ASCII_SIZE, f); 114 fclose(f); 115 116 pid = atoi(pid_ascii); 117 } 118 else 119 { 120 Log2(PCSC_LOG_CRITICAL, "Can't open " USE_RUN_PID ": %s", 121 strerror(errno)); 122 return -1; 123 } 124 125 return pid; 126} /* GetDaemonPid */ 127#endif 128 129int SendHotplugSignal(void) 130{ 131#ifdef USE_RUN_PID 132 pid_t pid; 133 134 pid = GetDaemonPid(); 135 136 if (pid != -1) 137 { 138 Log2(PCSC_LOG_INFO, "Send hotplug signal to pcscd (pid=%d)", pid); 139 if (kill(pid, SIGUSR1) < 0) 140 { 141 Log3(PCSC_LOG_CRITICAL, "Can't signal pcscd (pid=%d): %s", 142 pid, strerror(errno)); 143 return EXIT_FAILURE ; 144 } 145 } 146#endif 147 148 return EXIT_SUCCESS; 149} /* SendHotplugSignal */ 150 151int ProcessHotplugRequest() 152{ 153#ifdef USE_RUN_PID 154 155 /* read the pid file to get the old pid and test if the old pcscd is 156 * still running 157 */ 158 if (GetDaemonPid() != -1) 159 return SendHotplugSignal(); 160 161 Log1(PCSC_LOG_CRITICAL, "file " USE_RUN_PID " does not exist"); 162 Log1(PCSC_LOG_CRITICAL, "Perhaps pcscd is not running?"); 163#else 164 struct stat tmpStat; 165 if (SYS_Stat(PCSCLITE_CSOCK_NAME, &tmpStat) == 0) // socket file exists, so maybe pcscd is running 166 return SendHotplugSignal(); 167 Log1(PCSC_LOG_CRITICAL, "pcscd was not configured with --enable-runpid=FILE"); 168#endif 169 Log1(PCSC_LOG_CRITICAL, "Hotplug failed"); 170 return EXIT_FAILURE; 171} 172 173/* 174 * Cleans up messages still on the queue when a client dies 175 */ 176void SVCClientCleanup(psharedSegmentMsg msgStruct) 177{ 178 /* 179 * May be implemented in future releases 180 */ 181} 182 183/** 184 * @brief The Server's Message Queue Listener function. 185 * 186 * An endless loop calls the function \c SHMProcessEventsServer() to check for 187 * messages sent by clients. 188 * If the message is valid, \c CreateContextThread() is called to serve this 189 * request. 190 */ 191void SVCServiceRunLoop(void) 192{ 193 int rsp; 194 LONG rv; 195 DWORD dwClientID; /* Connection ID used to reference the Client */ 196 197 rsp = 0; 198 rv = 0; 199 200 /* 201 * Initialize the comm structure 202 */ 203 rsp = SHMInitializeCommonSegment(); 204 205 if (rsp == -1) 206 { 207 Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd."); 208 exit(-1); 209 } 210 211 /* 212 * Initialize the contexts structure 213 */ 214 rv = ContextsInitialize(); 215 216 if (rv == -1) 217 { 218 Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd."); 219 exit(-1); 220 } 221 222 /* 223 * Solaris sends a SIGALRM and it is annoying 224 */ 225 226 signal(SIGALRM, SIG_IGN); 227 signal(SIGPIPE, SIG_IGN); 228 signal(SIGHUP, SIG_IGN); /* needed for Solaris. The signal is sent 229 * when the shell is existed */ 230 231 /* 232 * This function always returns zero 233 */ 234 rsp = SYS_MutexInit(&usbNotifierMutex); 235 236 /* 237 * Set up the search for USB/PCMCIA devices 238 */ 239 HPSearchHotPluggables(); 240 HPRegisterForHotplugEvents(); 241 242 /* 243 * Set up the power management callback routine 244 */ 245// PMRegisterForPowerEvents(); 246 247 while (1) 248 { 249 switch (rsp = SHMProcessEventsServer(&dwClientID, 0)) 250 { 251 252 case 0: 253 Log2(PCSC_LOG_DEBUG, "A new context thread creation is requested: %d", dwClientID); 254 rv = CreateContextThread(&dwClientID); 255 256 if (rv != SCARD_S_SUCCESS) 257 { 258 Log1(PCSC_LOG_ERROR, "Problem during the context thread creation"); 259 AraKiri = 1; 260 } 261 262 break; 263 264 case 2: 265 /* 266 * timeout in SHMProcessEventsServer(): do nothing 267 * this is used to catch the Ctrl-C signal at some time when 268 * nothing else happens 269 */ 270 break; 271 272 case -1: 273 Log1(PCSC_LOG_ERROR, "Error in SHMProcessEventsServer"); 274 break; 275 276 case -2: 277 /* Nothing to do in case of a syscall interrupted 278 * It happens when SIGUSR1 (reload) or SIGINT (Ctrl-C) is received 279 * We just try again */ 280 break; 281 282 default: 283 Log2(PCSC_LOG_ERROR, "SHMProcessEventsServer unknown retval: %d", 284 rsp); 285 break; 286 } 287 288 if (AraKiri) 289 { 290 /* stop the hotpug thread and waits its exit */ 291 Log1(PCSC_LOG_ERROR, "Preparing to exit..."); 292 HPStopHotPluggables(); 293 SYS_Sleep(1); 294 295 /* now stop all the drivers */ 296 RFCleanupReaders(1); 297 } 298 } 299} 300 301int main(int argc, char **argv) 302{ 303 int rv; 304 char setToForeground; 305 char HotPlug; 306 char *newReaderConfig; 307 struct stat fStatBuf; 308 int opt; 309#ifdef HAVE_GETOPT_LONG 310 int option_index = 0; 311 static struct option long_options[] = { 312 {"config", 1, 0, 'c'}, 313 {"foreground", 0, 0, 'f'}, 314 {"help", 0, 0, 'h'}, 315 {"version", 0, 0, 'v'}, 316 {"apdu", 0, 0, 'a'}, 317 {"debug", 0, 0, 'd'}, 318 {"info", 0, 0, 0}, 319 {"error", 0, 0, 'e'}, 320 {"critical", 0, 0, 'C'}, 321 {"hotplug", 0, 0, 'H'}, 322 {"force-reader-polling", optional_argument, 0, 0}, 323 {0, 0, 0, 0} 324 }; 325#endif 326#define OPT_STRING "c:fdhvaeCH" 327 328 rv = 0; 329 newReaderConfig = NULL; 330 setToForeground = 0; 331 HotPlug = 0; 332 globalArgv = argv; 333 334 /* 335 * test the version 336 */ 337 if (strcmp(PCSCLITE_VERSION_NUMBER, VERSION) != 0) 338 { 339 printf("BUILD ERROR: The release version number PCSCLITE_VERSION_NUMBER\n"); 340 printf(" in pcsclite.h (%s) does not match the release version number\n", 341 PCSCLITE_VERSION_NUMBER); 342 printf(" generated in config.h (%s) (see configure.in).\n", VERSION); 343 344 return EXIT_FAILURE; 345 } 346 347 /* 348 * By default we create a daemon (not connected to any output) 349 * The log will go to wherever securityd log output goes. 350 */ 351 DebugLogSetLogType(DEBUGLOG_NO_DEBUG); 352 353 /* 354 * Handle any command line arguments 355 */ 356#ifdef HAVE_GETOPT_LONG 357 while ((opt = getopt_long (argc, argv, OPT_STRING, long_options, &option_index)) != -1) { 358#else 359 while ((opt = getopt (argc, argv, OPT_STRING)) != -1) { 360#endif 361 switch (opt) { 362#ifdef HAVE_GETOPT_LONG 363 case 0: 364 if (strcmp(long_options[option_index].name, 365 "force-reader-polling") == 0) 366 HPForceReaderPolling = optarg ? abs(atoi(optarg)) : 1; 367 break; 368#endif 369 case 'c': 370 Log2(PCSC_LOG_INFO, "using new config file: %s", optarg); 371 newReaderConfig = optarg; 372 break; 373 374 case 'f': 375 setToForeground = 1; 376 /* debug to stderr instead of default syslog */ 377 Log1(PCSC_LOG_INFO, 378 "pcscd set to foreground with debug send to stderr"); 379 break; 380 381 case 'd': 382 DebugLogSetLogType(DEBUGLOG_STDERR_DEBUG); 383 DebugLogSetLevel(PCSC_LOG_DEBUG); 384 break; 385 386 case 'e': 387 DebugLogSetLogType(DEBUGLOG_STDERR_DEBUG); 388 DebugLogSetLevel(PCSC_LOG_ERROR); 389 break; 390 391 case 'C': 392 DebugLogSetLogType(DEBUGLOG_STDERR_DEBUG); 393 DebugLogSetLevel(PCSC_LOG_CRITICAL); 394 break; 395 396 case 'h': 397 print_usage (argv[0]); 398 return EXIT_SUCCESS; 399 400 case 'v': 401 print_version (); 402 return EXIT_SUCCESS; 403 404 case 'a': 405 DebugLogSetCategory(DEBUG_CATEGORY_APDU); 406 break; 407 408 case 'H': 409 /* debug to stderr instead of default syslog */ 410 DebugLogSetLogType(DEBUGLOG_STDERR_DEBUG); 411 HotPlug = 1; 412 break; 413 414 default: 415 print_usage (argv[0]); 416 return EXIT_FAILURE; 417 } 418 419 } 420 421 if (argv[optind]) 422 { 423 printf("Unknown option: %s\n\n", argv[optind]); 424 print_usage(argv[0]); 425 return EXIT_SUCCESS; 426 } 427 428 /* 429 If this run of pcscd has the hotplug option, just send a signal to the 430 running one and exit 431 */ 432 433 if (HotPlug) 434 return ProcessHotplugRequest(); 435 436 /* 437 * test the presence of /var/run/pcsc.comm 438 */ 439 440 rv = SYS_Stat(PCSCLITE_CSOCK_NAME, &fStatBuf); 441 442 if (rv == 0) 443 { 444#ifdef USE_RUN_PID 445 pid_t pid; 446 447 /* read the pid file to get the old pid and test if the old pcscd is 448 * still running 449 */ 450 pid = GetDaemonPid(); 451 452 if (pid != -1) 453 { 454 if (kill(pid, 0) == 0) 455 { 456 Log2(PCSC_LOG_CRITICAL, 457 "Another pcscd (pid: %d) seems to be running.", pid); 458 Log1(PCSC_LOG_CRITICAL, 459 "Remove " USE_RUN_PID " if pcscd is not running to clear this message."); 460 return EXIT_FAILURE; 461 } 462 else 463 /* the old pcscd is dead. Do some cleanup */ 464 clean_temp_files(); 465 } 466#else 467 { 468 Log1(PCSC_LOG_CRITICAL, 469 "file " PCSCLITE_CSOCK_NAME " already exists."); 470 Log1(PCSC_LOG_CRITICAL, 471 "Maybe another pcscd is running?"); 472 Log1(PCSC_LOG_CRITICAL, 473 "Remove " PCSCLITE_CSOCK_NAME "if pcscd is not running to clear this message."); 474 return EXIT_FAILURE; 475 } 476#endif 477 } 478 479 /* 480 * If this is set to one the user has asked it not to fork 481 */ 482 if (!setToForeground) 483 { 484 if (SYS_Daemon(0, 0)) 485 Log2(PCSC_LOG_CRITICAL, "SYS_Daemon() failed: %s", 486 strerror(errno)); 487 } 488 489 /* 490 * cleanly remove /tmp/pcsc when exiting 491 */ 492 signal(SIGQUIT, signal_trap); 493 signal(SIGTERM, signal_trap); 494 signal(SIGINT, signal_trap); 495 signal(SIGHUP, signal_trap); 496 497#ifdef USE_RUN_PID 498 /* 499 * Record our pid to make it easier 500 * to kill the correct pcscd 501 */ 502 { 503 FILE *f; 504 505 if ((f = fopen(USE_RUN_PID, "wb")) != NULL) 506 { 507 fprintf(f, "%u\n", (unsigned) getpid()); 508 fclose(f); 509 } 510 } 511#endif 512 513 /* 514 * If PCSCLITE_IPC_DIR does not exist then create it 515 */ 516 rv = SYS_Stat(PCSCLITE_IPC_DIR, &fStatBuf); 517 if (rv < 0) 518 { 519 rv = SYS_Mkdir(PCSCLITE_IPC_DIR, S_ISVTX | S_IRWXO | S_IRWXG | S_IRWXU); 520 if (rv != 0) 521 { 522 Log2(PCSC_LOG_CRITICAL, 523 "cannot create " PCSCLITE_IPC_DIR ": %s", strerror(errno)); 524 return EXIT_FAILURE; 525 } 526 } 527 528 /* cleanly remove /var/run/pcsc.* files when exiting */ 529 if (atexit(at_exit)) 530 Log2(PCSC_LOG_CRITICAL, "atexit() failed: %s", strerror(errno)); 531 532 /* 533 * Allocate memory for reader structures 534 */ 535 RFAllocateReaderSpace(); 536 537 /* 538 Grab the information from the reader.conf. If a file has been specified 539 and there is any error, consider it fatal. If no file was explicitly 540 specified, ignore if file not present. 541 542 DBUpdateReaders returns: 543 544 1 if config file can't be opened 545 -1 if config file is broken 546 0 if all good 547 548 We skip this step if running in 64 bit mode, as serial readers are considered 549 legacy code. 550 */ 551 552 rv = RFStartSerialReaders(newReaderConfig?newReaderConfig:PCSCLITE_READER_CONFIG); 553 if (rv == -1) 554 { 555 Log3(PCSC_LOG_CRITICAL, "invalid file %s: %s", newReaderConfig, 556 strerror(errno)); 557 at_exit(); 558 } 559 else 560 if ((rv == 1) && newReaderConfig) 561 { 562 Log3(PCSC_LOG_CRITICAL, "file %s can't be opened: %s", 563 newReaderConfig, strerror(errno)); 564 at_exit(); 565 } 566 567 /* 568 * Set the default globals 569 */ 570 g_rgSCardT0Pci.dwProtocol = SCARD_PROTOCOL_T0; 571 g_rgSCardT1Pci.dwProtocol = SCARD_PROTOCOL_T1; 572 g_rgSCardRawPci.dwProtocol = SCARD_PROTOCOL_RAW; 573 574 Log1(PCSC_LOG_INFO, "pcsc-lite " VERSION " daemon ready."); 575 576 /* 577 * post initialistion 578 */ 579 Init = 0; 580 581 /* 582 * signal_trap() does just set a global variable used by the main loop 583 */ 584 signal(SIGQUIT, signal_trap); 585 signal(SIGTERM, signal_trap); 586 signal(SIGINT, signal_trap); 587 signal(SIGHUP, signal_trap); 588 589 signal(SIGUSR1, signal_reload); 590 591 SVCServiceRunLoop(); 592 593 Log1(PCSC_LOG_ERROR, "SVCServiceRunLoop returned"); 594 return EXIT_FAILURE; 595} 596 597void at_exit(void) 598{ 599 Log1(PCSC_LOG_INFO, "cleaning " PCSCLITE_IPC_DIR); 600 601 clean_temp_files(); 602 603 SYS_Exit(EXIT_SUCCESS); 604} 605 606void clean_temp_files(void) 607{ 608 int rv; 609 610 rv = SYS_Unlink(PCSCLITE_CSOCK_NAME); 611 if (rv != 0) 612 Log2(PCSC_LOG_ERROR, "Cannot unlink " PCSCLITE_CSOCK_NAME ": %s", 613 strerror(errno)); 614 615#ifdef USE_RUN_PID 616 rv = SYS_Unlink(USE_RUN_PID); 617 if (rv != 0) 618 Log2(PCSC_LOG_ERROR, "Cannot unlink " USE_RUN_PID ": %s", 619 strerror(errno)); 620#endif 621} 622 623void signal_reload(int sig) 624{ 625 static int rescan_ongoing = 0; 626 627 if (AraKiri) 628 return; 629 630 Log1(PCSC_LOG_INFO, "Reload serial configuration"); 631 if (rescan_ongoing) 632 { 633 Log1(PCSC_LOG_INFO, "Rescan already ongoing"); 634 return; 635 } 636 637 rescan_ongoing = 0; 638 639 HPReCheckSerialReaders(); 640 641 rescan_ongoing = 0; 642 Log1(PCSC_LOG_INFO, "End reload serial configuration"); 643} /* signal_reload */ 644 645void signal_trap(int sig) 646{ 647 /* the signal handler is called several times for the same Ctrl-C */ 648 if (AraKiri == 0) 649 { 650 Log1(PCSC_LOG_INFO, "Preparing for suicide"); 651 AraKiri = 1; 652 653 /* if still in the init/loading phase the AraKiri will not be 654 * seen by the main event loop 655 */ 656 if (Init) 657 { 658 Log1(PCSC_LOG_INFO, "Suicide during init"); 659 at_exit(); 660 } 661 } 662} 663 664#if MAX_OS_X_VERSION_MIN_REQUIRED <= MAX_OS_X_VERSION_10_5 665 #include <spawn.h> 666 #include <err.h> 667 #include <CoreFoundation/CFBundle.h> 668 #include <CoreFoundation/CFNumber.h> 669#endif 670 671extern char **environ; 672void print_version (void) 673{ 674 printf("%s version %s.\n", PACKAGE, VERSION); 675 printf("Copyright (C) 1999-2002 by David Corcoran <corcoran@linuxnet.com>.\n"); 676 printf("Copyright (C) 2001-2005 by Ludovic Rousseau <ludovic.rousseau@free.fr>.\n"); 677 printf("Copyright (C) 2003-2004 by Damien Sauveron <sauveron@labri.fr>.\n"); 678 printf("Portions Copyright (C) 2000-2007 by Apple Inc.\n"); 679 printf("Report bugs to <sclinux@linuxnet.com>.\n"); 680} 681 682void print_usage (char const * const progname) 683{ 684 printf("Usage: %s options\n", progname); 685 printf("Options:\n"); 686#ifdef HAVE_GETOPT_LONG 687 printf(" -a, --apdu log APDU commands and results\n"); 688 printf(" -c, --config path to reader.conf\n"); 689 printf(" -f, --foreground run in foreground (no daemon),\n"); 690 printf(" send logs to stderr instead of syslog\n"); 691 printf(" -h, --help display usage information\n"); 692 printf(" -H, --hotplug ask the daemon to rescan the available readers\n"); 693 printf(" -v, --version display the program version number\n"); 694 printf(" -d, --debug display lower level debug messages\n"); 695 printf(" --info display info level debug messages (default level)\n"); 696 printf(" -e --error display error level debug messages\n"); 697 printf(" -C --critical display critical only level debug messages\n"); 698 printf(" --force-reader-polling ignore the IFD_GENERATE_HOTPLUG reader capability\n"); 699#else 700 printf(" -a log APDU commands and results\n"); 701 printf(" -c path to reader.conf\n"); 702 printf(" -f run in foreground (no daemon), send logs to stderr instead of syslog\n"); 703 printf(" -d display debug messages. Output may be:\n"); 704 printf(" -h display usage information\n"); 705 printf(" -H ask the daemon to rescan the avaiable readers\n"); 706 printf(" -v display the program version number\n"); 707#endif 708} 709 710