~ubuntu-branches/ubuntu/jaunty/pcsc-lite/jaunty-security

« back to all changes in this revision

Viewing changes to src/pcscdaemon.c

  • Committer: Bazaar Package Importer
  • Author(s): Ludovic Rousseau
  • Date: 2005-11-27 18:04:59 UTC
  • mfrom: (1.2.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20051127180459-qrex2gzpq9d8jexd
Tags: 1.2.9-beta9-1
* New upstream version
* debian/compat: change from 3 to 4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * MUSCLE SmartCard Development ( http://www.linuxnet.com )
 
3
 *
 
4
 * Copyright (C) 1999-2005
 
5
 *  David Corcoran <corcoran@linuxnet.com>
 
6
 *  Ludovic Rousseau <ludovic.rousseau@free.fr>
 
7
 *
 
8
 * $Id: pcscdaemon.c 1565 2005-06-27 08:42:33Z rousseau $
 
9
 */
 
10
 
 
11
/**
 
12
 * @file
 
13
 * @brief This is the main pcscd daemon.
 
14
 *
 
15
 * The function \c main() starts up the communication environment.\n
 
16
 * Then an endless loop is calld to look for Client connections. For each
 
17
 * Client connection a call to \c CreateContextThread() is done.
 
18
 */
 
19
 
 
20
#include "config.h"
 
21
#include <time.h>
 
22
#include <syslog.h>
 
23
#include <signal.h>
 
24
#include <sys/types.h>
 
25
#include <sys/stat.h>
 
26
#include <errno.h>
 
27
#include <stdio.h>
 
28
#include <unistd.h>
 
29
#include <stdlib.h>
 
30
#include <string.h>
 
31
#ifdef HAVE_GETOPT_H
 
32
#include <getopt.h>
 
33
#endif
 
34
 
 
35
#include "pcsclite.h"
 
36
#include "debuglog.h"
 
37
#include "winscard_msg.h"
 
38
#include "winscard_svc.h"
 
39
#include "sys_generic.h"
 
40
#include "thread_generic.h"
 
41
#include "hotplug.h"
 
42
#include "readerfactory.h"
 
43
#include "configfile.h"
 
44
#include "powermgt_generic.h"
 
45
 
 
46
#ifndef TRUE
 
47
#define TRUE 1
 
48
#define FALSE 0
 
49
#endif
 
50
 
 
51
char AraKiri = FALSE;
 
52
static char Init = TRUE;
 
53
extern char ReCheckSerialReaders;
 
54
 
 
55
/*
 
56
 * Some internal functions 
 
57
 */
 
58
void SVCServiceRunLoop(void);
 
59
void SVCClientCleanup(psharedSegmentMsg);
 
60
void at_exit(void);
 
61
void clean_temp_files(void);
 
62
void signal_reload(int sig);
 
63
void signal_trap(int);
 
64
void print_version (void);
 
65
void print_usage (char const * const);
 
66
 
 
67
PCSCLITE_MUTEX usbNotifierMutex;
 
68
 
 
69
/*
 
70
 * Cleans up messages still on the queue when a client dies 
 
71
 */
 
72
void SVCClientCleanup(psharedSegmentMsg msgStruct)
 
73
{
 
74
        /*
 
75
         * May be implemented in future releases 
 
76
         */
 
77
}
 
78
 
 
79
/**
 
80
 * @brief The Server's Message Queue Listener function.
 
81
 *
 
82
 * An endless loop calls the function \c SHMProcessEventsServer() to check for
 
83
 * messages sent by clients.
 
84
 * If the message is valid, \c CreateContextThread() is called to serve this 
 
85
 * request.
 
86
 */
 
87
void SVCServiceRunLoop(void)
 
88
{
 
89
        int rsp;
 
90
        LONG rv;
 
91
        DWORD dwClientID;       /* Connection ID used to reference the Client */
 
92
        
 
93
        rsp = 0;
 
94
        rv = 0;
 
95
 
 
96
        /*
 
97
         * Initialize the comm structure 
 
98
         */
 
99
        rsp = SHMInitializeCommonSegment();
 
100
 
 
101
        if (rsp == -1)
 
102
        {
 
103
                Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
 
104
                exit(-1);
 
105
        }
 
106
 
 
107
        /*
 
108
         * Initialize the contexts structure 
 
109
         */
 
110
        rv = ContextsInitialize();
 
111
 
 
112
        if (rv == -1)
 
113
        {
 
114
                Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
 
115
                exit(-1);
 
116
        }
 
117
 
 
118
        /*
 
119
         * Solaris sends a SIGALRM and it is annoying 
 
120
         */
 
121
 
 
122
        signal(SIGALRM, SIG_IGN);
 
123
        signal(SIGPIPE, SIG_IGN);
 
124
        signal(SIGHUP, SIG_IGN);        /* needed for Solaris. The signal is sent
 
125
                                 * when the shell is existed */
 
126
 
 
127
        /*
 
128
         * This function always returns zero 
 
129
         */
 
130
        rsp = SYS_MutexInit(&usbNotifierMutex);
 
131
 
 
132
        /*
 
133
         * Set up the search for USB/PCMCIA devices 
 
134
         */
 
135
        HPSearchHotPluggables();
 
136
        HPRegisterForHotplugEvents();
 
137
 
 
138
        /*
 
139
         * Set up the power management callback routine
 
140
         */
 
141
        PMRegisterForPowerEvents();
 
142
 
 
143
        while (TRUE)
 
144
        {
 
145
 
 
146
                switch (rsp = SHMProcessEventsServer(&dwClientID, 0))
 
147
                {
 
148
 
 
149
                case 0:
 
150
                        Log2(PCSC_LOG_DEBUG, "A new context thread creation is requested: %d", dwClientID);
 
151
                        rv = CreateContextThread(&dwClientID);
 
152
 
 
153
                        if (rv != SCARD_S_SUCCESS)
 
154
                        {
 
155
                                Log1(PCSC_LOG_ERROR, "Problem during the context thread creation");
 
156
                                AraKiri = TRUE;
 
157
                        }
 
158
 
 
159
                        break;
 
160
 
 
161
                case 2:
 
162
                        /*
 
163
                         * timeout in SHMProcessEventsServer(): do nothing
 
164
                         * this is used to catch the Ctrl-C signal at some time when
 
165
                         * nothing else happens
 
166
                         */
 
167
                        break;
 
168
 
 
169
                case -1:
 
170
                        /* do not display if we are exiting or re-reading the config */
 
171
                        if ((!AraKiri) && (!ReCheckSerialReaders))
 
172
                                Log1(PCSC_LOG_ERROR, "Error in SHMProcessEventsServer");
 
173
                        break;
 
174
 
 
175
                default:
 
176
                        Log2(PCSC_LOG_ERROR, "SHMProcessEventsServer unknown retval: %d",
 
177
                                rsp);
 
178
                        break;
 
179
                }
 
180
 
 
181
                if (AraKiri)
 
182
                {
 
183
                        /* stop the hotpug thread and waits its exit */
 
184
                        HPStopHotPluggables();
 
185
                        SYS_Sleep(1);
 
186
 
 
187
                        /* now stop all the drivers */
 
188
                        RFCleanupReaders(1);
 
189
                }
 
190
        }
 
191
}
 
192
 
 
193
int main(int argc, char **argv)
 
194
{
 
195
        int rv;
 
196
        char setToForeground;
 
197
        char *newReaderConfig;
 
198
        struct stat fStatBuf;
 
199
        int opt;
 
200
#ifdef HAVE_GETOPT_LONG
 
201
        int option_index = 0;
 
202
        static struct option long_options[] = {
 
203
                {"config", 1, 0, 'c'},
 
204
                {"foreground", 0, 0, 'f'},
 
205
                {"help", 0, 0, 'h'},
 
206
                {"version", 0, 0, 'v'},
 
207
                {"apdu", 0, 0, 'a'},
 
208
                {"debug", 0, 0, 'd'},
 
209
                {"info", 0, 0, 0},
 
210
                {"error", 0, 0, 'e'},
 
211
                {"critical", 0, 0, 'C'},
 
212
                {0, 0, 0, 0}
 
213
        };
 
214
#endif
 
215
        
 
216
        rv = 0;
 
217
        newReaderConfig = 0;
 
218
        setToForeground = FALSE;
 
219
 
 
220
        /*
 
221
         * test the version 
 
222
         */
 
223
        if (strcmp(PCSCLITE_VERSION_NUMBER, VERSION) != 0)
 
224
        {
 
225
                printf("BUILD ERROR: The release version number PCSCLITE_VERSION_NUMBER\n");
 
226
                printf("  in pcsclite.h (%s) does not match the release version number\n",
 
227
                        PCSCLITE_VERSION_NUMBER);
 
228
                printf("  generated in config.h (%s) (see configure.in).\n", VERSION);
 
229
 
 
230
                return EXIT_FAILURE;
 
231
        }
 
232
 
 
233
        /*
 
234
         * By default we create a daemon (not connected to any output)
 
235
         * so log to syslog to have error messages.
 
236
         */
 
237
        DebugLogSetLogType(DEBUGLOG_SYSLOG_DEBUG);
 
238
 
 
239
        /*
 
240
         * Handle any command line arguments 
 
241
         */
 
242
#ifdef  HAVE_GETOPT_LONG
 
243
        while ((opt = getopt_long (argc, argv, "c:fdhvaeC", long_options, &option_index)) != -1) {
 
244
#else
 
245
        while ((opt = getopt (argc, argv, "c:fdhvaeC")) != -1) {
 
246
#endif
 
247
                switch (opt) {
 
248
                        case 'c':
 
249
                                Log2(PCSC_LOG_INFO, "using new config file: %s", optarg);
 
250
                                newReaderConfig = optarg;
 
251
                                break;
 
252
 
 
253
                        case 'f':
 
254
                                setToForeground = TRUE;
 
255
                                /* debug to stderr instead of default syslog */
 
256
                                DebugLogSetLogType(DEBUGLOG_STDERR_DEBUG);
 
257
                                Log1(PCSC_LOG_INFO,
 
258
                                        "pcscd set to foreground with debug send to stderr");
 
259
                                break;
 
260
 
 
261
                        case 'd':
 
262
                                DebugLogSetLevel(PCSC_LOG_DEBUG);
 
263
                                break;
 
264
 
 
265
                        case 'e':
 
266
                                DebugLogSetLevel(PCSC_LOG_ERROR);
 
267
                                break;
 
268
 
 
269
                        case 'C':
 
270
                                DebugLogSetLevel(PCSC_LOG_CRITICAL);
 
271
                                break;
 
272
 
 
273
                        case 'h':
 
274
                                print_usage (argv[0]);
 
275
                                return EXIT_SUCCESS;
 
276
 
 
277
                        case 'v':
 
278
                                print_version ();
 
279
                                return EXIT_SUCCESS;
 
280
 
 
281
                        case 'a':
 
282
                                DebugLogSetCategory(DEBUG_CATEGORY_APDU);
 
283
                                break;
 
284
 
 
285
                        default:
 
286
                                print_usage (argv[0]);
 
287
                                return EXIT_FAILURE;
 
288
                }
 
289
 
 
290
        }
 
291
        
 
292
        if (argv[optind])
 
293
        {
 
294
                printf("Unknown option: %s\n\n", argv[optind]);
 
295
                print_usage(argv[0]);
 
296
                return EXIT_SUCCESS;
 
297
        }
 
298
 
 
299
        /*
 
300
         * test the presence of /var/run/pcsc.pub
 
301
         */
 
302
 
 
303
        rv = SYS_Stat(PCSCLITE_PUBSHM_FILE, &fStatBuf);
 
304
 
 
305
        if (rv == 0)
 
306
        {
 
307
#ifdef USE_RUN_PID
 
308
 
 
309
                /* read the pid file to get the old pid and test if the old pcscd is
 
310
                 * still running 
 
311
                 */
 
312
                FILE *f;
 
313
                /* pids are only 15 bits but 4294967296
 
314
                 * (32 bits in case of a new system use it) is on 10 bytes
 
315
                 */
 
316
#define PID_ASCII_SIZE 11
 
317
                char pid_ascii[PID_ASCII_SIZE];
 
318
                int pid;
 
319
 
 
320
                if ((f = fopen(USE_RUN_PID, "rb")) != NULL)
 
321
                {
 
322
                        fgets(pid_ascii, PID_ASCII_SIZE, f);
 
323
                        fclose(f);
 
324
 
 
325
                        pid = atoi(pid_ascii);
 
326
 
 
327
                        if (kill(pid, 0) == 0)
 
328
                        {
 
329
                                Log1(PCSC_LOG_CRITICAL,
 
330
                                        "file " PCSCLITE_PUBSHM_FILE " already exists.");
 
331
                                Log2(PCSC_LOG_CRITICAL,
 
332
                                        "Another pcscd (pid: %d) seems to be running.", pid);
 
333
                                return EXIT_FAILURE;
 
334
                        }
 
335
                        else
 
336
                                /* the old pcscd is dead. make some cleanup */
 
337
                                clean_temp_files();
 
338
                }
 
339
                else
 
340
                {
 
341
                        Log1(PCSC_LOG_CRITICAL,
 
342
                                "file " PCSCLITE_PUBSHM_FILE " already exists.");
 
343
                        Log1(PCSC_LOG_CRITICAL,
 
344
                                "Maybe another pcscd is running?");
 
345
                        Log1(PCSC_LOG_CRITICAL, 
 
346
                                "I can't read process pid from " USE_RUN_PID);
 
347
                        Log1(PCSC_LOG_CRITICAL,
 
348
                                "Remove " PCSCLITE_PUBSHM_FILE " and " PCSCLITE_CSOCK_NAME);
 
349
                        Log1(PCSC_LOG_CRITICAL,
 
350
                                "if pcscd is not running to clear this message.");
 
351
                        return EXIT_FAILURE;
 
352
                }
 
353
#else
 
354
                Log1(PCSC_LOG_CRITICAL,
 
355
                        "file " PCSCLITE_PUBSHM_FILE " already exists.");
 
356
                Log1(PCSC_LOG_CRITICAL,
 
357
                        "Maybe another pcscd is running?");
 
358
                Log1(PCSC_LOG_CRITICAL,
 
359
                        "Remove " PCSCLITE_PUBSHM_FILE " and " PCSCLITE_CSOCK_NAME);
 
360
                Log1(PCSC_LOG_CRITICAL,
 
361
                        "if pcscd is not running to clear this message.");
 
362
                return EXIT_FAILURE;
 
363
#endif
 
364
        }
 
365
 
 
366
        /*
 
367
         * If this is set to one the user has asked it not to fork 
 
368
         */
 
369
        if (!setToForeground)
 
370
        {
 
371
                if (SYS_Daemon(0, 0))
 
372
                        Log2(PCSC_LOG_CRITICAL, "SYS_Daemon() failed: %s",
 
373
                                strerror(errno));
 
374
        }
 
375
 
 
376
        /*
 
377
         * cleanly remove /tmp/pcsc when exiting 
 
378
         */
 
379
        signal(SIGQUIT, signal_trap);
 
380
        signal(SIGTERM, signal_trap);
 
381
        signal(SIGINT, signal_trap);
 
382
        signal(SIGHUP, signal_trap);
 
383
 
 
384
#ifdef USE_RUN_PID
 
385
        /*
 
386
         * Record our pid to make it easier
 
387
         * to kill the correct pcscd
 
388
         */
 
389
        {
 
390
                FILE *f;
 
391
 
 
392
                if ((f = fopen(USE_RUN_PID, "wb")) != NULL)
 
393
                {
 
394
                        fprintf(f, "%u\n", (unsigned) getpid());
 
395
                        fclose(f);
 
396
                }
 
397
        }
 
398
#endif
 
399
 
 
400
        /*
 
401
         * If PCSCLITE_IPC_DIR does not exist then create it
 
402
         */
 
403
        rv = SYS_Stat(PCSCLITE_IPC_DIR, &fStatBuf);
 
404
        if (rv < 0)
 
405
        {
 
406
                rv = SYS_Mkdir(PCSCLITE_IPC_DIR, S_ISVTX | S_IRWXO | S_IRWXG | S_IRWXU);
 
407
                if (rv != 0)
 
408
                {
 
409
                        Log2(PCSC_LOG_CRITICAL,
 
410
                                "cannot create " PCSCLITE_IPC_DIR ": %s", strerror(errno));
 
411
                        return EXIT_FAILURE;
 
412
                }
 
413
        }
 
414
 
 
415
        /* cleanly remove /var/run/pcsc.* files when exiting */
 
416
        if (atexit(at_exit))
 
417
                Log2(PCSC_LOG_CRITICAL, "atexit() failed: %s", strerror(errno));
 
418
 
 
419
        /*
 
420
         * Allocate memory for reader structures 
 
421
         */
 
422
        RFAllocateReaderSpace();
 
423
 
 
424
        /*
 
425
         * Grab the information from the reader.conf 
 
426
         */
 
427
        if (newReaderConfig)
 
428
        {
 
429
                rv = RFStartSerialReaders(newReaderConfig);
 
430
                if (rv != 0)
 
431
                {
 
432
                        Log3(PCSC_LOG_CRITICAL, "invalid file %s: %s", newReaderConfig,
 
433
                                strerror(errno));
 
434
                        at_exit();
 
435
                }
 
436
        }
 
437
        else
 
438
        {
 
439
                rv = RFStartSerialReaders(PCSCLITE_READER_CONFIG);
 
440
 
 
441
#if 0
 
442
                if (rv == 1)
 
443
                {
 
444
                        Log1(PCSC_LOG_INFO,
 
445
                                "warning: no " PCSCLITE_READER_CONFIG " found");
 
446
                        /*
 
447
                         * Token error in file 
 
448
                         */
 
449
                }
 
450
                else
 
451
#endif
 
452
                        if (rv == -1)
 
453
                                at_exit();
 
454
        }
 
455
 
 
456
        /*
 
457
         * Set the default globals 
 
458
         */
 
459
        g_rgSCardT0Pci.dwProtocol = SCARD_PROTOCOL_T0;
 
460
        g_rgSCardT1Pci.dwProtocol = SCARD_PROTOCOL_T1;
 
461
        g_rgSCardRawPci.dwProtocol = SCARD_PROTOCOL_RAW;
 
462
 
 
463
        Log1(PCSC_LOG_INFO, "pcsc-lite " VERSION " daemon ready.");
 
464
 
 
465
        /*
 
466
         * post initialistion 
 
467
         */
 
468
        Init = FALSE;
 
469
 
 
470
        /*
 
471
         * signal_trap() does just set a global variable used by the main loop 
 
472
         */
 
473
        signal(SIGQUIT, signal_trap);
 
474
        signal(SIGTERM, signal_trap);
 
475
        signal(SIGINT, signal_trap);
 
476
        signal(SIGHUP, signal_trap);
 
477
 
 
478
        signal(SIGUSR1, signal_reload);
 
479
 
 
480
        SVCServiceRunLoop();
 
481
 
 
482
        Log1(PCSC_LOG_ERROR, "SVCServiceRunLoop returned");
 
483
        return EXIT_FAILURE;
 
484
}
 
485
 
 
486
void at_exit(void)
 
487
{
 
488
        Log1(PCSC_LOG_INFO, "cleaning " PCSCLITE_IPC_DIR);
 
489
 
 
490
        clean_temp_files();
 
491
 
 
492
        SYS_Exit(EXIT_SUCCESS);
 
493
}
 
494
 
 
495
void clean_temp_files(void)
 
496
{
 
497
        int rv;
 
498
 
 
499
        rv = SYS_Unlink(PCSCLITE_PUBSHM_FILE);
 
500
        if (rv != 0)
 
501
                Log2(PCSC_LOG_ERROR, "Cannot unlink " PCSCLITE_PUBSHM_FILE ": %s",
 
502
                        strerror(errno));
 
503
 
 
504
        rv = SYS_Unlink(PCSCLITE_CSOCK_NAME);
 
505
        if (rv != 0)
 
506
                Log2(PCSC_LOG_ERROR, "Cannot unlink " PCSCLITE_CSOCK_NAME ": %s",
 
507
                        strerror(errno));
 
508
 
 
509
#ifdef USE_RUN_PID
 
510
        rv = SYS_Unlink(USE_RUN_PID);
 
511
        if (rv != 0)
 
512
                Log2(PCSC_LOG_ERROR, "Cannot unlink " USE_RUN_PID ": %s",
 
513
                        strerror(errno));
 
514
#endif
 
515
}
 
516
 
 
517
void signal_reload(int sig)
 
518
{
 
519
        Log1(PCSC_LOG_INFO, "Reload serial configuration");
 
520
        HPReCheckSerialReaders();
 
521
} /* signal_reload */
 
522
 
 
523
void signal_trap(int sig)
 
524
{
 
525
        /* the signal handler is called several times for the same Ctrl-C */
 
526
        if (AraKiri == FALSE)
 
527
        {
 
528
                Log1(PCSC_LOG_INFO, "Preparing for suicide");
 
529
                AraKiri = TRUE;
 
530
 
 
531
                /* if still in the init/loading phase the AraKiri will not be
 
532
                 * seen by the main event loop
 
533
                 */
 
534
                if (Init)
 
535
                {
 
536
                        Log1(PCSC_LOG_INFO, "Suicide during init");
 
537
                        at_exit();
 
538
                }
 
539
        }
 
540
}
 
541
 
 
542
void print_version (void)
 
543
{
 
544
        printf("%s version %s.\n",  PACKAGE, VERSION);
 
545
        printf("Copyright (C) 1999-2002 by David Corcoran <corcoran@linuxnet.com>.\n");
 
546
        printf("Copyright (C) 2001-2005 by Ludovic Rousseau <ludovic.rousseau@free.fr>.\n");
 
547
        printf("Copyright (C) 2003-2004 by Damien Sauveron <sauveron@labri.fr>.\n");
 
548
        printf("Report bugs to <sclinux@linuxnet.com>.\n");
 
549
}
 
550
 
 
551
void print_usage (char const * const progname)
 
552
{
 
553
        printf("Usage: %s options\n", progname);
 
554
        printf("Options:\n");
 
555
#ifdef HAVE_GETOPT_LONG
 
556
        printf("  -a, --apdu            log APDU commands and results\n");
 
557
        printf("  -c, --config          path to reader.conf\n");
 
558
        printf("  -f, --foreground      run in foreground (no daemon),\n");
 
559
        printf("                        send logs to stderr instead of syslog\n");
 
560
        printf("  -h, --help            display usage information\n");
 
561
        printf("  -v, --version         display the program version number\n");
 
562
        printf("  -d, --debug           display lower level debug messages\n"); 
 
563
        printf("      --info            display info level debug messages (default level)\n"); 
 
564
        printf("  -e  --error           display error level debug messages\n"); 
 
565
        printf("  -C  --critical        display critical only level debug messages\n"); 
 
566
#else
 
567
        printf("  -a    log APDU commands and results\n");
 
568
        printf("  -c    path to reader.conf\n");
 
569
        printf("  -f    run in foreground (no daemon), send logs to stderr instead of syslog\n");
 
570
        printf("  -d    display debug messages. Output may be:\n"); 
 
571
        printf("  -h    display usage information\n");
 
572
        printf("  -v    display the program version number\n");
 
573
#endif
 
574
}
 
575