Statistics
| Branch: | Revision:

root / libcacard / vcard_emul_nss.c @ 992aeb8e

History | View | Annotate | Download (37.9 kB)

1 111a38b0 Robert Relyea
/*
2 111a38b0 Robert Relyea
 * This is the actual card emulator.
3 111a38b0 Robert Relyea
 *
4 111a38b0 Robert Relyea
 * These functions can be implemented in different ways on different platforms
5 111a38b0 Robert Relyea
 * using the underlying system primitives. For Linux it uses NSS, though direct
6 111a38b0 Robert Relyea
 * to PKCS #11, openssl+pkcs11, or even gnu crypto libraries+pkcs #11 could be
7 111a38b0 Robert Relyea
 * used. On Windows CAPI could be used.
8 111a38b0 Robert Relyea
 *
9 111a38b0 Robert Relyea
 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
10 111a38b0 Robert Relyea
 * See the COPYING.LIB file in the top-level directory.
11 111a38b0 Robert Relyea
 */
12 111a38b0 Robert Relyea
13 111a38b0 Robert Relyea
/*
14 111a38b0 Robert Relyea
 * NSS headers
15 111a38b0 Robert Relyea
 */
16 111a38b0 Robert Relyea
17 111a38b0 Robert Relyea
/* avoid including prototypes.h that redefines uint32 */
18 111a38b0 Robert Relyea
#define NO_NSPR_10_SUPPORT
19 111a38b0 Robert Relyea
20 111a38b0 Robert Relyea
#include <nss.h>
21 111a38b0 Robert Relyea
#include <pk11pub.h>
22 111a38b0 Robert Relyea
#include <cert.h>
23 111a38b0 Robert Relyea
#include <key.h>
24 111a38b0 Robert Relyea
#include <secmod.h>
25 111a38b0 Robert Relyea
#include <prthread.h>
26 111a38b0 Robert Relyea
#include <secerr.h>
27 111a38b0 Robert Relyea
28 111a38b0 Robert Relyea
#include "qemu-common.h"
29 111a38b0 Robert Relyea
30 111a38b0 Robert Relyea
#include "vcard.h"
31 111a38b0 Robert Relyea
#include "card_7816t.h"
32 111a38b0 Robert Relyea
#include "vcard_emul.h"
33 111a38b0 Robert Relyea
#include "vreader.h"
34 111a38b0 Robert Relyea
#include "vevent.h"
35 111a38b0 Robert Relyea
36 010debef Robert Relyea
typedef enum {
37 010debef Robert Relyea
    VCardEmulUnknown = -1,
38 010debef Robert Relyea
    VCardEmulFalse = 0,
39 010debef Robert Relyea
    VCardEmulTrue = 1
40 010debef Robert Relyea
} VCardEmulTriState;
41 010debef Robert Relyea
42 111a38b0 Robert Relyea
struct VCardKeyStruct {
43 111a38b0 Robert Relyea
    CERTCertificate *cert;
44 111a38b0 Robert Relyea
    PK11SlotInfo *slot;
45 111a38b0 Robert Relyea
    SECKEYPrivateKey *key;
46 010debef Robert Relyea
    VCardEmulTriState failedX509;
47 111a38b0 Robert Relyea
};
48 111a38b0 Robert Relyea
49 111a38b0 Robert Relyea
50 111a38b0 Robert Relyea
typedef struct VirtualReaderOptionsStruct VirtualReaderOptions;
51 111a38b0 Robert Relyea
52 111a38b0 Robert Relyea
struct VReaderEmulStruct {
53 111a38b0 Robert Relyea
    PK11SlotInfo *slot;
54 111a38b0 Robert Relyea
    VCardEmulType default_type;
55 111a38b0 Robert Relyea
    char *type_params;
56 111a38b0 Robert Relyea
    PRBool present;
57 111a38b0 Robert Relyea
    int     series;
58 111a38b0 Robert Relyea
    VCard *saved_vcard;
59 111a38b0 Robert Relyea
};
60 111a38b0 Robert Relyea
61 111a38b0 Robert Relyea
/*
62 111a38b0 Robert Relyea
 *  NSS Specific options
63 111a38b0 Robert Relyea
 */
64 111a38b0 Robert Relyea
struct VirtualReaderOptionsStruct {
65 111a38b0 Robert Relyea
    char *name;
66 111a38b0 Robert Relyea
    char *vname;
67 111a38b0 Robert Relyea
    VCardEmulType card_type;
68 111a38b0 Robert Relyea
    char *type_params;
69 111a38b0 Robert Relyea
    char **cert_name;
70 111a38b0 Robert Relyea
    int cert_count;
71 111a38b0 Robert Relyea
};
72 111a38b0 Robert Relyea
73 111a38b0 Robert Relyea
struct VCardEmulOptionsStruct {
74 111a38b0 Robert Relyea
    void *nss_db;
75 111a38b0 Robert Relyea
    VirtualReaderOptions *vreader;
76 111a38b0 Robert Relyea
    int vreader_count;
77 111a38b0 Robert Relyea
    VCardEmulType hw_card_type;
78 111a38b0 Robert Relyea
    const char *hw_type_params;
79 111a38b0 Robert Relyea
    PRBool use_hw;
80 111a38b0 Robert Relyea
};
81 111a38b0 Robert Relyea
82 111a38b0 Robert Relyea
static int nss_emul_init;
83 111a38b0 Robert Relyea
84 111a38b0 Robert Relyea
/* if we have more that just the slot, define
85 111a38b0 Robert Relyea
 * VCardEmulStruct here */
86 111a38b0 Robert Relyea
87 111a38b0 Robert Relyea
/*
88 111a38b0 Robert Relyea
 * allocate the set of arrays for certs, cert_len, key
89 111a38b0 Robert Relyea
 */
90 111a38b0 Robert Relyea
static PRBool
91 111a38b0 Robert Relyea
vcard_emul_alloc_arrays(unsigned char ***certsp, int **cert_lenp,
92 111a38b0 Robert Relyea
                        VCardKey ***keysp, int cert_count)
93 111a38b0 Robert Relyea
{
94 111a38b0 Robert Relyea
    *certsp = NULL;
95 111a38b0 Robert Relyea
    *cert_lenp = NULL;
96 111a38b0 Robert Relyea
    *keysp = NULL;
97 7267c094 Anthony Liguori
    *certsp = (unsigned char **)g_malloc(sizeof(unsigned char *)*cert_count);
98 7267c094 Anthony Liguori
    *cert_lenp = (int *)g_malloc(sizeof(int)*cert_count);
99 7267c094 Anthony Liguori
    *keysp = (VCardKey **)g_malloc(sizeof(VCardKey *)*cert_count);
100 111a38b0 Robert Relyea
    return PR_TRUE;
101 111a38b0 Robert Relyea
}
102 111a38b0 Robert Relyea
103 111a38b0 Robert Relyea
/*
104 111a38b0 Robert Relyea
 * Emulator specific card information
105 111a38b0 Robert Relyea
 */
106 111a38b0 Robert Relyea
typedef struct CardEmulCardStruct CardEmulPrivate;
107 111a38b0 Robert Relyea
108 111a38b0 Robert Relyea
static VCardEmul *
109 111a38b0 Robert Relyea
vcard_emul_new_card(PK11SlotInfo *slot)
110 111a38b0 Robert Relyea
{
111 111a38b0 Robert Relyea
    PK11_ReferenceSlot(slot);
112 111a38b0 Robert Relyea
    /* currently we don't need anything other than the slot */
113 111a38b0 Robert Relyea
    return (VCardEmul *)slot;
114 111a38b0 Robert Relyea
}
115 111a38b0 Robert Relyea
116 111a38b0 Robert Relyea
static void
117 111a38b0 Robert Relyea
vcard_emul_delete_card(VCardEmul *vcard_emul)
118 111a38b0 Robert Relyea
{
119 111a38b0 Robert Relyea
    PK11SlotInfo *slot = (PK11SlotInfo *)vcard_emul;
120 111a38b0 Robert Relyea
    if (slot == NULL) {
121 111a38b0 Robert Relyea
        return;
122 111a38b0 Robert Relyea
    }
123 111a38b0 Robert Relyea
    PK11_FreeSlot(slot);
124 111a38b0 Robert Relyea
}
125 111a38b0 Robert Relyea
126 111a38b0 Robert Relyea
static PK11SlotInfo *
127 111a38b0 Robert Relyea
vcard_emul_card_get_slot(VCard *card)
128 111a38b0 Robert Relyea
{
129 111a38b0 Robert Relyea
    /* note, the card is holding the reference, no need to get another one */
130 111a38b0 Robert Relyea
    return (PK11SlotInfo *)vcard_get_private(card);
131 111a38b0 Robert Relyea
}
132 111a38b0 Robert Relyea
133 111a38b0 Robert Relyea
134 111a38b0 Robert Relyea
/*
135 111a38b0 Robert Relyea
 * key functions
136 111a38b0 Robert Relyea
 */
137 111a38b0 Robert Relyea
/* private constructure */
138 111a38b0 Robert Relyea
static VCardKey *
139 111a38b0 Robert Relyea
vcard_emul_make_key(PK11SlotInfo *slot, CERTCertificate *cert)
140 111a38b0 Robert Relyea
{
141 111a38b0 Robert Relyea
    VCardKey *key;
142 111a38b0 Robert Relyea
143 7267c094 Anthony Liguori
    key = (VCardKey *)g_malloc(sizeof(VCardKey));
144 111a38b0 Robert Relyea
    key->slot = PK11_ReferenceSlot(slot);
145 111a38b0 Robert Relyea
    key->cert = CERT_DupCertificate(cert);
146 111a38b0 Robert Relyea
    /* NOTE: if we aren't logged into the token, this could return NULL */
147 111a38b0 Robert Relyea
    /* NOTE: the cert is a temp cert, not necessarily the cert in the token,
148 111a38b0 Robert Relyea
     * use the DER version of this function */
149 111a38b0 Robert Relyea
    key->key = PK11_FindKeyByDERCert(slot, cert, NULL);
150 010debef Robert Relyea
    key->failedX509 = VCardEmulUnknown;
151 111a38b0 Robert Relyea
    return key;
152 111a38b0 Robert Relyea
}
153 111a38b0 Robert Relyea
154 111a38b0 Robert Relyea
/* destructor */
155 111a38b0 Robert Relyea
void
156 111a38b0 Robert Relyea
vcard_emul_delete_key(VCardKey *key)
157 111a38b0 Robert Relyea
{
158 111a38b0 Robert Relyea
    if (!nss_emul_init || (key == NULL)) {
159 111a38b0 Robert Relyea
        return;
160 111a38b0 Robert Relyea
    }
161 111a38b0 Robert Relyea
    if (key->key) {
162 111a38b0 Robert Relyea
        SECKEY_DestroyPrivateKey(key->key);
163 111a38b0 Robert Relyea
        key->key = NULL;
164 111a38b0 Robert Relyea
    }
165 111a38b0 Robert Relyea
    if (key->cert) {
166 111a38b0 Robert Relyea
        CERT_DestroyCertificate(key->cert);
167 111a38b0 Robert Relyea
    }
168 111a38b0 Robert Relyea
    if (key->slot) {
169 111a38b0 Robert Relyea
        PK11_FreeSlot(key->slot);
170 111a38b0 Robert Relyea
    }
171 111a38b0 Robert Relyea
}
172 111a38b0 Robert Relyea
173 111a38b0 Robert Relyea
/*
174 111a38b0 Robert Relyea
 * grab the nss key from a VCardKey. If it doesn't exist, try to look it up
175 111a38b0 Robert Relyea
 */
176 111a38b0 Robert Relyea
static SECKEYPrivateKey *
177 111a38b0 Robert Relyea
vcard_emul_get_nss_key(VCardKey *key)
178 111a38b0 Robert Relyea
{
179 111a38b0 Robert Relyea
    if (key->key) {
180 111a38b0 Robert Relyea
        return key->key;
181 111a38b0 Robert Relyea
    }
182 111a38b0 Robert Relyea
    /* NOTE: if we aren't logged into the token, this could return NULL */
183 111a38b0 Robert Relyea
    key->key = PK11_FindPrivateKeyFromCert(key->slot, key->cert, NULL);
184 111a38b0 Robert Relyea
    return key->key;
185 111a38b0 Robert Relyea
}
186 111a38b0 Robert Relyea
187 111a38b0 Robert Relyea
/*
188 111a38b0 Robert Relyea
 * Map NSS errors to 7816 errors
189 111a38b0 Robert Relyea
 */
190 111a38b0 Robert Relyea
static vcard_7816_status_t
191 111a38b0 Robert Relyea
vcard_emul_map_error(int error)
192 111a38b0 Robert Relyea
{
193 111a38b0 Robert Relyea
    switch (error) {
194 111a38b0 Robert Relyea
    case SEC_ERROR_TOKEN_NOT_LOGGED_IN:
195 111a38b0 Robert Relyea
        return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
196 111a38b0 Robert Relyea
    case SEC_ERROR_BAD_DATA:
197 111a38b0 Robert Relyea
    case SEC_ERROR_OUTPUT_LEN:
198 111a38b0 Robert Relyea
    case SEC_ERROR_INPUT_LEN:
199 111a38b0 Robert Relyea
    case SEC_ERROR_INVALID_ARGS:
200 111a38b0 Robert Relyea
    case SEC_ERROR_INVALID_ALGORITHM:
201 111a38b0 Robert Relyea
    case SEC_ERROR_NO_KEY:
202 111a38b0 Robert Relyea
    case SEC_ERROR_INVALID_KEY:
203 111a38b0 Robert Relyea
    case SEC_ERROR_DECRYPTION_DISALLOWED:
204 111a38b0 Robert Relyea
        return VCARD7816_STATUS_ERROR_DATA_INVALID;
205 111a38b0 Robert Relyea
    case SEC_ERROR_NO_MEMORY:
206 111a38b0 Robert Relyea
        return VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE;
207 111a38b0 Robert Relyea
    }
208 111a38b0 Robert Relyea
    return VCARD7816_STATUS_EXC_ERROR_CHANGE;
209 111a38b0 Robert Relyea
}
210 111a38b0 Robert Relyea
211 111a38b0 Robert Relyea
/* RSA sign/decrypt with the key, signature happens 'in place' */
212 111a38b0 Robert Relyea
vcard_7816_status_t
213 111a38b0 Robert Relyea
vcard_emul_rsa_op(VCard *card, VCardKey *key,
214 111a38b0 Robert Relyea
                  unsigned char *buffer, int buffer_size)
215 111a38b0 Robert Relyea
{
216 111a38b0 Robert Relyea
    SECKEYPrivateKey *priv_key;
217 111a38b0 Robert Relyea
    unsigned signature_len;
218 010debef Robert Relyea
    PK11SlotInfo *slot;
219 111a38b0 Robert Relyea
    SECStatus rv;
220 010debef Robert Relyea
    unsigned char buf[2048];
221 010debef Robert Relyea
    unsigned char *bp = NULL;
222 010debef Robert Relyea
    int pad_len;
223 010debef Robert Relyea
    vcard_7816_status_t ret = VCARD7816_STATUS_SUCCESS;
224 111a38b0 Robert Relyea
225 111a38b0 Robert Relyea
    if ((!nss_emul_init) || (key == NULL)) {
226 111a38b0 Robert Relyea
        /* couldn't get the key, indicate that we aren't logged in */
227 111a38b0 Robert Relyea
        return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
228 111a38b0 Robert Relyea
    }
229 111a38b0 Robert Relyea
    priv_key = vcard_emul_get_nss_key(key);
230 010debef Robert Relyea
    if (priv_key == NULL) {
231 010debef Robert Relyea
        /* couldn't get the key, indicate that we aren't logged in */
232 010debef Robert Relyea
        return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
233 010debef Robert Relyea
    }
234 010debef Robert Relyea
    slot = vcard_emul_card_get_slot(card);
235 111a38b0 Robert Relyea
236 111a38b0 Robert Relyea
    /*
237 111a38b0 Robert Relyea
     * this is only true of the rsa signature
238 111a38b0 Robert Relyea
     */
239 111a38b0 Robert Relyea
    signature_len = PK11_SignatureLen(priv_key);
240 111a38b0 Robert Relyea
    if (buffer_size != signature_len) {
241 111a38b0 Robert Relyea
        return  VCARD7816_STATUS_ERROR_DATA_INVALID;
242 111a38b0 Robert Relyea
    }
243 010debef Robert Relyea
    /* be able to handle larger keys if necessariy */
244 010debef Robert Relyea
    bp = &buf[0];
245 010debef Robert Relyea
    if (sizeof(buf) < signature_len) {
246 7267c094 Anthony Liguori
        bp = g_malloc(signature_len);
247 010debef Robert Relyea
    }
248 010debef Robert Relyea
249 010debef Robert Relyea
    /*
250 010debef Robert Relyea
     * do the raw operations. Some tokens claim to do CKM_RSA_X_509, but then
251 010debef Robert Relyea
     * choke when they try to do the actual operations. Try to detect
252 010debef Robert Relyea
     * those cases and treat them as if the token didn't claim support for
253 010debef Robert Relyea
     * X_509.
254 010debef Robert Relyea
     */
255 010debef Robert Relyea
    if (key->failedX509 != VCardEmulTrue
256 010debef Robert Relyea
                              && PK11_DoesMechanism(slot, CKM_RSA_X_509)) {
257 010debef Robert Relyea
        rv = PK11_PrivDecryptRaw(priv_key, bp, &signature_len, signature_len,
258 010debef Robert Relyea
                                 buffer, buffer_size);
259 010debef Robert Relyea
        if (rv == SECSuccess) {
260 010debef Robert Relyea
            assert(buffer_size == signature_len);
261 010debef Robert Relyea
            memcpy(buffer, bp, signature_len);
262 010debef Robert Relyea
            key->failedX509 = VCardEmulFalse;
263 010debef Robert Relyea
            goto cleanup;
264 010debef Robert Relyea
        }
265 010debef Robert Relyea
        /*
266 010debef Robert Relyea
         * we've had a successful X509 operation, this failure must be
267 010debef Robert Relyea
         * somethine else
268 010debef Robert Relyea
         */
269 010debef Robert Relyea
        if (key->failedX509 == VCardEmulFalse) {
270 010debef Robert Relyea
            ret = vcard_emul_map_error(PORT_GetError());
271 010debef Robert Relyea
            goto cleanup;
272 010debef Robert Relyea
        }
273 010debef Robert Relyea
        /*
274 010debef Robert Relyea
         * key->failedX509 must be Unknown at this point, try the
275 010debef Robert Relyea
         * non-x_509 case
276 010debef Robert Relyea
         */
277 010debef Robert Relyea
    }
278 010debef Robert Relyea
    /* token does not support CKM_RSA_X509, emulate that with CKM_RSA_PKCS */
279 010debef Robert Relyea
    /* is this a PKCS #1 formatted signature? */
280 010debef Robert Relyea
    if ((buffer[0] == 0) && (buffer[1] == 1)) {
281 010debef Robert Relyea
        int i;
282 010debef Robert Relyea
283 010debef Robert Relyea
        for (i = 2; i < buffer_size; i++) {
284 010debef Robert Relyea
            /* rsa signature pad */
285 010debef Robert Relyea
            if (buffer[i] != 0xff) {
286 010debef Robert Relyea
                break;
287 010debef Robert Relyea
            }
288 010debef Robert Relyea
        }
289 010debef Robert Relyea
        if ((i < buffer_size) && (buffer[i] == 0)) {
290 010debef Robert Relyea
            /* yes, we have a properly formated PKCS #1 signature */
291 010debef Robert Relyea
            /*
292 010debef Robert Relyea
             * NOTE: even if we accidentally got an encrypt buffer, which
293 010debef Robert Relyea
             * through shear luck started with 00, 01, ff, 00, it won't matter
294 010debef Robert Relyea
             * because the resulting Sign operation will effectively decrypt
295 010debef Robert Relyea
             * the real buffer.
296 010debef Robert Relyea
             */
297 010debef Robert Relyea
            SECItem signature;
298 010debef Robert Relyea
            SECItem hash;
299 010debef Robert Relyea
300 010debef Robert Relyea
            i++;
301 010debef Robert Relyea
            hash.data = &buffer[i];
302 010debef Robert Relyea
            hash.len = buffer_size - i;
303 010debef Robert Relyea
            signature.data = bp;
304 010debef Robert Relyea
            signature.len = signature_len;
305 010debef Robert Relyea
            rv = PK11_Sign(priv_key,  &signature, &hash);
306 010debef Robert Relyea
            if (rv != SECSuccess) {
307 010debef Robert Relyea
                ret = vcard_emul_map_error(PORT_GetError());
308 010debef Robert Relyea
                goto cleanup;
309 010debef Robert Relyea
            }
310 010debef Robert Relyea
            assert(buffer_size == signature.len);
311 010debef Robert Relyea
            memcpy(buffer, bp, signature.len);
312 010debef Robert Relyea
            /*
313 010debef Robert Relyea
             * we got here because either the X509 attempt failed, or the
314 010debef Robert Relyea
             * token couldn't do the X509 operation, in either case stay
315 010debef Robert Relyea
             * with the PKCS version for future operations on this key
316 010debef Robert Relyea
             */
317 010debef Robert Relyea
            key->failedX509 = VCardEmulTrue;
318 010debef Robert Relyea
            goto cleanup;
319 010debef Robert Relyea
        }
320 010debef Robert Relyea
    }
321 010debef Robert Relyea
    pad_len = buffer_size - signature_len;
322 010debef Robert Relyea
    assert(pad_len < 4);
323 010debef Robert Relyea
    /*
324 010debef Robert Relyea
     * OK now we've decrypted the payload, package it up in PKCS #1 for the
325 010debef Robert Relyea
     * upper layer.
326 010debef Robert Relyea
     */
327 010debef Robert Relyea
    buffer[0] = 0;
328 010debef Robert Relyea
    buffer[1] = 2; /* RSA_encrypt  */
329 010debef Robert Relyea
    pad_len -= 3; /* format is 0 || 2 || pad || 0 || data */
330 010debef Robert Relyea
    /*
331 010debef Robert Relyea
     * padding for PKCS #1 encrypted data is a string of random bytes. The
332 010debef Robert Relyea
     * random butes protect against potential decryption attacks against RSA.
333 010debef Robert Relyea
     * Since PrivDecrypt has already stripped those bytes, we can't reconstruct
334 010debef Robert Relyea
     * them. This shouldn't matter to the upper level code which should just
335 010debef Robert Relyea
     * strip this code out anyway, so We'll pad with a constant 3.
336 010debef Robert Relyea
     */
337 010debef Robert Relyea
    memset(&buffer[2], 0x03, pad_len);
338 010debef Robert Relyea
    pad_len += 2; /* index to the end of the pad */
339 010debef Robert Relyea
    buffer[pad_len] = 0;
340 010debef Robert Relyea
    pad_len++; /* index to the start of the data */
341 010debef Robert Relyea
    memcpy(&buffer[pad_len], bp, signature_len);
342 010debef Robert Relyea
    /*
343 010debef Robert Relyea
     * we got here because either the X509 attempt failed, or the
344 010debef Robert Relyea
     * token couldn't do the X509 operation, in either case stay
345 010debef Robert Relyea
     * with the PKCS version for future operations on this key
346 010debef Robert Relyea
     */
347 010debef Robert Relyea
    key->failedX509 = VCardEmulTrue;
348 010debef Robert Relyea
cleanup:
349 010debef Robert Relyea
    if (bp != buf) {
350 7267c094 Anthony Liguori
        g_free(bp);
351 111a38b0 Robert Relyea
    }
352 010debef Robert Relyea
    return ret;
353 111a38b0 Robert Relyea
}
354 111a38b0 Robert Relyea
355 111a38b0 Robert Relyea
/*
356 111a38b0 Robert Relyea
 * Login functions
357 111a38b0 Robert Relyea
 */
358 111a38b0 Robert Relyea
/* return the number of login attempts still possible on the card. if unknown,
359 111a38b0 Robert Relyea
 * return -1 */
360 111a38b0 Robert Relyea
int
361 111a38b0 Robert Relyea
vcard_emul_get_login_count(VCard *card)
362 111a38b0 Robert Relyea
{
363 111a38b0 Robert Relyea
    return -1;
364 111a38b0 Robert Relyea
}
365 111a38b0 Robert Relyea
366 111a38b0 Robert Relyea
/* login into the card, return the 7816 status word (sw2 || sw1) */
367 111a38b0 Robert Relyea
vcard_7816_status_t
368 111a38b0 Robert Relyea
vcard_emul_login(VCard *card, unsigned char *pin, int pin_len)
369 111a38b0 Robert Relyea
{
370 111a38b0 Robert Relyea
    PK11SlotInfo *slot;
371 111a38b0 Robert Relyea
    unsigned char *pin_string = NULL;
372 111a38b0 Robert Relyea
    int i;
373 111a38b0 Robert Relyea
    SECStatus rv;
374 111a38b0 Robert Relyea
375 111a38b0 Robert Relyea
    if (!nss_emul_init) {
376 111a38b0 Robert Relyea
        return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
377 111a38b0 Robert Relyea
    }
378 111a38b0 Robert Relyea
    slot = vcard_emul_card_get_slot(card);
379 111a38b0 Robert Relyea
     /* We depend on the PKCS #11 module internal login state here because we
380 111a38b0 Robert Relyea
      * create a separate process to handle each guest instance. If we needed
381 111a38b0 Robert Relyea
      * to handle multiple guests from one process, then we would need to keep
382 111a38b0 Robert Relyea
      * a lot of extra state in our card structure
383 111a38b0 Robert Relyea
      * */
384 7267c094 Anthony Liguori
    pin_string = g_malloc(pin_len+1);
385 111a38b0 Robert Relyea
    memcpy(pin_string, pin, pin_len);
386 111a38b0 Robert Relyea
    pin_string[pin_len] = 0;
387 111a38b0 Robert Relyea
388 111a38b0 Robert Relyea
    /* handle CAC expanded pins correctly */
389 111a38b0 Robert Relyea
    for (i = pin_len-1; i >= 0 && (pin_string[i] == 0xff); i--) {
390 111a38b0 Robert Relyea
        pin_string[i] = 0;
391 111a38b0 Robert Relyea
    }
392 111a38b0 Robert Relyea
393 111a38b0 Robert Relyea
    rv = PK11_Authenticate(slot, PR_FALSE, pin_string);
394 111a38b0 Robert Relyea
    memset(pin_string, 0, pin_len);  /* don't let the pin hang around in memory
395 111a38b0 Robert Relyea
                                        to be snooped */
396 7267c094 Anthony Liguori
    g_free(pin_string);
397 111a38b0 Robert Relyea
    if (rv == SECSuccess) {
398 111a38b0 Robert Relyea
        return VCARD7816_STATUS_SUCCESS;
399 111a38b0 Robert Relyea
    }
400 111a38b0 Robert Relyea
    /* map the error from port get error */
401 111a38b0 Robert Relyea
    return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
402 111a38b0 Robert Relyea
}
403 111a38b0 Robert Relyea
404 111a38b0 Robert Relyea
void
405 111a38b0 Robert Relyea
vcard_emul_reset(VCard *card, VCardPower power)
406 111a38b0 Robert Relyea
{
407 111a38b0 Robert Relyea
    PK11SlotInfo *slot;
408 111a38b0 Robert Relyea
409 111a38b0 Robert Relyea
    if (!nss_emul_init) {
410 111a38b0 Robert Relyea
        return;
411 111a38b0 Robert Relyea
    }
412 111a38b0 Robert Relyea
413 111a38b0 Robert Relyea
    /*
414 111a38b0 Robert Relyea
     * if we reset the card (either power on or power off), we lose our login
415 111a38b0 Robert Relyea
     * state
416 111a38b0 Robert Relyea
     */
417 111a38b0 Robert Relyea
    /* TODO: we may also need to send insertion/removal events? */
418 111a38b0 Robert Relyea
    slot = vcard_emul_card_get_slot(card);
419 111a38b0 Robert Relyea
    PK11_Logout(slot); /* NOTE: ignoring SECStatus return value */
420 111a38b0 Robert Relyea
}
421 111a38b0 Robert Relyea
422 111a38b0 Robert Relyea
423 111a38b0 Robert Relyea
static VReader *
424 111a38b0 Robert Relyea
vcard_emul_find_vreader_from_slot(PK11SlotInfo *slot)
425 111a38b0 Robert Relyea
{
426 111a38b0 Robert Relyea
    VReaderList *reader_list = vreader_get_reader_list();
427 111a38b0 Robert Relyea
    VReaderListEntry *current_entry = NULL;
428 111a38b0 Robert Relyea
429 111a38b0 Robert Relyea
    if (reader_list == NULL) {
430 111a38b0 Robert Relyea
        return NULL;
431 111a38b0 Robert Relyea
    }
432 111a38b0 Robert Relyea
    for (current_entry = vreader_list_get_first(reader_list); current_entry;
433 111a38b0 Robert Relyea
                        current_entry = vreader_list_get_next(current_entry)) {
434 111a38b0 Robert Relyea
        VReader *reader = vreader_list_get_reader(current_entry);
435 111a38b0 Robert Relyea
        VReaderEmul *reader_emul = vreader_get_private(reader);
436 111a38b0 Robert Relyea
        if (reader_emul->slot == slot) {
437 111a38b0 Robert Relyea
            return reader;
438 111a38b0 Robert Relyea
        }
439 111a38b0 Robert Relyea
        vreader_free(reader);
440 111a38b0 Robert Relyea
    }
441 111a38b0 Robert Relyea
442 111a38b0 Robert Relyea
    return NULL;
443 111a38b0 Robert Relyea
}
444 111a38b0 Robert Relyea
445 111a38b0 Robert Relyea
/*
446 111a38b0 Robert Relyea
 * create a new reader emul
447 111a38b0 Robert Relyea
 */
448 111a38b0 Robert Relyea
static VReaderEmul *
449 111a38b0 Robert Relyea
vreader_emul_new(PK11SlotInfo *slot, VCardEmulType type, const char *params)
450 111a38b0 Robert Relyea
{
451 111a38b0 Robert Relyea
    VReaderEmul *new_reader_emul;
452 111a38b0 Robert Relyea
453 7267c094 Anthony Liguori
    new_reader_emul = (VReaderEmul *)g_malloc(sizeof(VReaderEmul));
454 111a38b0 Robert Relyea
455 111a38b0 Robert Relyea
    new_reader_emul->slot = PK11_ReferenceSlot(slot);
456 111a38b0 Robert Relyea
    new_reader_emul->default_type = type;
457 111a38b0 Robert Relyea
    new_reader_emul->type_params = strdup(params);
458 111a38b0 Robert Relyea
    new_reader_emul->present = PR_FALSE;
459 111a38b0 Robert Relyea
    new_reader_emul->series = 0;
460 111a38b0 Robert Relyea
    new_reader_emul->saved_vcard = NULL;
461 111a38b0 Robert Relyea
    return new_reader_emul;
462 111a38b0 Robert Relyea
}
463 111a38b0 Robert Relyea
464 111a38b0 Robert Relyea
static void
465 111a38b0 Robert Relyea
vreader_emul_delete(VReaderEmul *vreader_emul)
466 111a38b0 Robert Relyea
{
467 111a38b0 Robert Relyea
    if (vreader_emul == NULL) {
468 111a38b0 Robert Relyea
        return;
469 111a38b0 Robert Relyea
    }
470 111a38b0 Robert Relyea
    if (vreader_emul->slot) {
471 111a38b0 Robert Relyea
        PK11_FreeSlot(vreader_emul->slot);
472 111a38b0 Robert Relyea
    }
473 111a38b0 Robert Relyea
    if (vreader_emul->type_params) {
474 7267c094 Anthony Liguori
        g_free(vreader_emul->type_params);
475 111a38b0 Robert Relyea
    }
476 7267c094 Anthony Liguori
    g_free(vreader_emul);
477 111a38b0 Robert Relyea
}
478 111a38b0 Robert Relyea
479 111a38b0 Robert Relyea
/*
480 111a38b0 Robert Relyea
 *  TODO: move this to emulater non-specific file
481 111a38b0 Robert Relyea
 */
482 111a38b0 Robert Relyea
static VCardEmulType
483 111a38b0 Robert Relyea
vcard_emul_get_type(VReader *vreader)
484 111a38b0 Robert Relyea
{
485 111a38b0 Robert Relyea
    VReaderEmul *vreader_emul;
486 111a38b0 Robert Relyea
487 111a38b0 Robert Relyea
    vreader_emul = vreader_get_private(vreader);
488 111a38b0 Robert Relyea
    if (vreader_emul && vreader_emul->default_type != VCARD_EMUL_NONE) {
489 111a38b0 Robert Relyea
        return vreader_emul->default_type;
490 111a38b0 Robert Relyea
    }
491 111a38b0 Robert Relyea
492 111a38b0 Robert Relyea
    return vcard_emul_type_select(vreader);
493 111a38b0 Robert Relyea
}
494 111a38b0 Robert Relyea
/*
495 111a38b0 Robert Relyea
 *  TODO: move this to emulater non-specific file
496 111a38b0 Robert Relyea
 */
497 111a38b0 Robert Relyea
static const char *
498 111a38b0 Robert Relyea
vcard_emul_get_type_params(VReader *vreader)
499 111a38b0 Robert Relyea
{
500 111a38b0 Robert Relyea
    VReaderEmul *vreader_emul;
501 111a38b0 Robert Relyea
502 111a38b0 Robert Relyea
    vreader_emul = vreader_get_private(vreader);
503 111a38b0 Robert Relyea
    if (vreader_emul && vreader_emul->type_params) {
504 111a38b0 Robert Relyea
        return vreader_emul->type_params;
505 111a38b0 Robert Relyea
    }
506 111a38b0 Robert Relyea
507 111a38b0 Robert Relyea
    return "";
508 111a38b0 Robert Relyea
}
509 111a38b0 Robert Relyea
510 111a38b0 Robert Relyea
/* pull the slot out of the reader private data */
511 111a38b0 Robert Relyea
static PK11SlotInfo *
512 111a38b0 Robert Relyea
vcard_emul_reader_get_slot(VReader *vreader)
513 111a38b0 Robert Relyea
{
514 111a38b0 Robert Relyea
    VReaderEmul *vreader_emul = vreader_get_private(vreader);
515 111a38b0 Robert Relyea
    if (vreader_emul == NULL) {
516 111a38b0 Robert Relyea
        return NULL;
517 111a38b0 Robert Relyea
    }
518 111a38b0 Robert Relyea
    return vreader_emul->slot;
519 111a38b0 Robert Relyea
}
520 111a38b0 Robert Relyea
521 111a38b0 Robert Relyea
/*
522 111a38b0 Robert Relyea
 *  Card ATR's map to physical cards. VCARD_ATR_PREFIX will set appropriate
523 111a38b0 Robert Relyea
 *  historical bytes for any software emulated card. The remaining bytes can be
524 111a38b0 Robert Relyea
 *  used to indicate the actual emulator
525 111a38b0 Robert Relyea
 */
526 111a38b0 Robert Relyea
static const unsigned char nss_atr[] = { VCARD_ATR_PREFIX(3), 'N', 'S', 'S' };
527 111a38b0 Robert Relyea
528 111a38b0 Robert Relyea
void
529 111a38b0 Robert Relyea
vcard_emul_get_atr(VCard *card, unsigned char *atr, int *atr_len)
530 111a38b0 Robert Relyea
{
531 111a38b0 Robert Relyea
    int len = MIN(sizeof(nss_atr), *atr_len);
532 111a38b0 Robert Relyea
    assert(atr != NULL);
533 111a38b0 Robert Relyea
534 111a38b0 Robert Relyea
    memcpy(atr, nss_atr, len);
535 111a38b0 Robert Relyea
    *atr_len = len;
536 111a38b0 Robert Relyea
}
537 111a38b0 Robert Relyea
538 111a38b0 Robert Relyea
/*
539 111a38b0 Robert Relyea
 * create a new card from certs and keys
540 111a38b0 Robert Relyea
 */
541 111a38b0 Robert Relyea
static VCard *
542 111a38b0 Robert Relyea
vcard_emul_make_card(VReader *reader,
543 111a38b0 Robert Relyea
                     unsigned char * const *certs, int *cert_len,
544 111a38b0 Robert Relyea
                     VCardKey *keys[], int cert_count)
545 111a38b0 Robert Relyea
{
546 111a38b0 Robert Relyea
    VCardEmul *vcard_emul;
547 111a38b0 Robert Relyea
    VCard *vcard;
548 111a38b0 Robert Relyea
    PK11SlotInfo *slot;
549 111a38b0 Robert Relyea
    VCardEmulType type;
550 111a38b0 Robert Relyea
    const char *params;
551 111a38b0 Robert Relyea
552 111a38b0 Robert Relyea
    type = vcard_emul_get_type(reader);
553 111a38b0 Robert Relyea
554 111a38b0 Robert Relyea
    /* ignore the inserted card */
555 111a38b0 Robert Relyea
    if (type == VCARD_EMUL_NONE) {
556 111a38b0 Robert Relyea
        return NULL;
557 111a38b0 Robert Relyea
    }
558 111a38b0 Robert Relyea
    slot = vcard_emul_reader_get_slot(reader);
559 111a38b0 Robert Relyea
    if (slot == NULL) {
560 111a38b0 Robert Relyea
        return NULL;
561 111a38b0 Robert Relyea
    }
562 111a38b0 Robert Relyea
563 111a38b0 Robert Relyea
    params = vcard_emul_get_type_params(reader);
564 111a38b0 Robert Relyea
    /* params these can be NULL */
565 111a38b0 Robert Relyea
566 111a38b0 Robert Relyea
    vcard_emul = vcard_emul_new_card(slot);
567 111a38b0 Robert Relyea
    if (vcard_emul == NULL) {
568 111a38b0 Robert Relyea
        return NULL;
569 111a38b0 Robert Relyea
    }
570 111a38b0 Robert Relyea
    vcard = vcard_new(vcard_emul, vcard_emul_delete_card);
571 111a38b0 Robert Relyea
    if (vcard == NULL) {
572 111a38b0 Robert Relyea
        vcard_emul_delete_card(vcard_emul);
573 111a38b0 Robert Relyea
        return NULL;
574 111a38b0 Robert Relyea
    }
575 111a38b0 Robert Relyea
    vcard_init(reader, vcard, type, params, certs, cert_len, keys, cert_count);
576 111a38b0 Robert Relyea
    return vcard;
577 111a38b0 Robert Relyea
}
578 111a38b0 Robert Relyea
579 111a38b0 Robert Relyea
580 111a38b0 Robert Relyea
/*
581 111a38b0 Robert Relyea
 * 'clone' a physical card as a virtual card
582 111a38b0 Robert Relyea
 */
583 111a38b0 Robert Relyea
static VCard *
584 111a38b0 Robert Relyea
vcard_emul_mirror_card(VReader *vreader)
585 111a38b0 Robert Relyea
{
586 111a38b0 Robert Relyea
    /*
587 111a38b0 Robert Relyea
     * lookup certs using the C_FindObjects. The Stan Cert handle won't give
588 111a38b0 Robert Relyea
     * us the real certs until we log in.
589 111a38b0 Robert Relyea
     */
590 111a38b0 Robert Relyea
    PK11GenericObject *firstObj, *thisObj;
591 111a38b0 Robert Relyea
    int cert_count;
592 111a38b0 Robert Relyea
    unsigned char **certs;
593 111a38b0 Robert Relyea
    int *cert_len;
594 111a38b0 Robert Relyea
    VCardKey **keys;
595 111a38b0 Robert Relyea
    PK11SlotInfo *slot;
596 111a38b0 Robert Relyea
    PRBool ret;
597 ee83d414 Christophe Fergeau
    VCard *card;
598 111a38b0 Robert Relyea
599 111a38b0 Robert Relyea
    slot = vcard_emul_reader_get_slot(vreader);
600 111a38b0 Robert Relyea
    if (slot == NULL) {
601 111a38b0 Robert Relyea
        return NULL;
602 111a38b0 Robert Relyea
    }
603 111a38b0 Robert Relyea
604 111a38b0 Robert Relyea
    firstObj = PK11_FindGenericObjects(slot, CKO_CERTIFICATE);
605 111a38b0 Robert Relyea
    if (firstObj == NULL) {
606 111a38b0 Robert Relyea
        return NULL;
607 111a38b0 Robert Relyea
    }
608 111a38b0 Robert Relyea
609 111a38b0 Robert Relyea
    /* count the certs */
610 111a38b0 Robert Relyea
    cert_count = 0;
611 111a38b0 Robert Relyea
    for (thisObj = firstObj; thisObj;
612 111a38b0 Robert Relyea
                             thisObj = PK11_GetNextGenericObject(thisObj)) {
613 111a38b0 Robert Relyea
        cert_count++;
614 111a38b0 Robert Relyea
    }
615 111a38b0 Robert Relyea
616 111a38b0 Robert Relyea
    if (cert_count == 0) {
617 111a38b0 Robert Relyea
        PK11_DestroyGenericObjects(firstObj);
618 111a38b0 Robert Relyea
        return NULL;
619 111a38b0 Robert Relyea
    }
620 111a38b0 Robert Relyea
621 111a38b0 Robert Relyea
    /* allocate the arrays */
622 111a38b0 Robert Relyea
    ret = vcard_emul_alloc_arrays(&certs, &cert_len, &keys, cert_count);
623 111a38b0 Robert Relyea
    if (ret == PR_FALSE) {
624 111a38b0 Robert Relyea
        return NULL;
625 111a38b0 Robert Relyea
    }
626 111a38b0 Robert Relyea
627 111a38b0 Robert Relyea
    /* fill in the arrays */
628 111a38b0 Robert Relyea
    cert_count = 0;
629 111a38b0 Robert Relyea
    for (thisObj = firstObj; thisObj;
630 111a38b0 Robert Relyea
                             thisObj = PK11_GetNextGenericObject(thisObj)) {
631 111a38b0 Robert Relyea
        SECItem derCert;
632 111a38b0 Robert Relyea
        CERTCertificate *cert;
633 111a38b0 Robert Relyea
        SECStatus rv;
634 111a38b0 Robert Relyea
635 111a38b0 Robert Relyea
        rv = PK11_ReadRawAttribute(PK11_TypeGeneric, thisObj,
636 111a38b0 Robert Relyea
                                   CKA_VALUE, &derCert);
637 111a38b0 Robert Relyea
        if (rv != SECSuccess) {
638 111a38b0 Robert Relyea
            continue;
639 111a38b0 Robert Relyea
        }
640 111a38b0 Robert Relyea
        /* create floating temp cert. This gives us a cert structure even if
641 111a38b0 Robert Relyea
         * the token isn't logged in */
642 111a38b0 Robert Relyea
        cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &derCert,
643 111a38b0 Robert Relyea
                                       NULL, PR_FALSE, PR_TRUE);
644 111a38b0 Robert Relyea
        SECITEM_FreeItem(&derCert, PR_FALSE);
645 111a38b0 Robert Relyea
        if (cert == NULL) {
646 111a38b0 Robert Relyea
            continue;
647 111a38b0 Robert Relyea
        }
648 111a38b0 Robert Relyea
649 111a38b0 Robert Relyea
        certs[cert_count] = cert->derCert.data;
650 111a38b0 Robert Relyea
        cert_len[cert_count] = cert->derCert.len;
651 111a38b0 Robert Relyea
        keys[cert_count] = vcard_emul_make_key(slot, cert);
652 111a38b0 Robert Relyea
        cert_count++;
653 111a38b0 Robert Relyea
        CERT_DestroyCertificate(cert); /* key obj still has a reference */
654 111a38b0 Robert Relyea
    }
655 111a38b0 Robert Relyea
656 111a38b0 Robert Relyea
    /* now create the card */
657 ee83d414 Christophe Fergeau
    card = vcard_emul_make_card(vreader, certs, cert_len, keys, cert_count);
658 7267c094 Anthony Liguori
    g_free(certs);
659 7267c094 Anthony Liguori
    g_free(cert_len);
660 7267c094 Anthony Liguori
    g_free(keys);
661 ee83d414 Christophe Fergeau
662 ee83d414 Christophe Fergeau
    return card;
663 111a38b0 Robert Relyea
}
664 111a38b0 Robert Relyea
665 111a38b0 Robert Relyea
static VCardEmulType default_card_type = VCARD_EMUL_NONE;
666 111a38b0 Robert Relyea
static const char *default_type_params = "";
667 111a38b0 Robert Relyea
668 111a38b0 Robert Relyea
/*
669 111a38b0 Robert Relyea
 * This thread looks for card and reader insertions and puts events on the
670 111a38b0 Robert Relyea
 * event queue
671 111a38b0 Robert Relyea
 */
672 111a38b0 Robert Relyea
static void
673 111a38b0 Robert Relyea
vcard_emul_event_thread(void *arg)
674 111a38b0 Robert Relyea
{
675 111a38b0 Robert Relyea
    PK11SlotInfo *slot;
676 111a38b0 Robert Relyea
    VReader *vreader;
677 111a38b0 Robert Relyea
    VReaderEmul *vreader_emul;
678 111a38b0 Robert Relyea
    VCard *vcard;
679 111a38b0 Robert Relyea
    SECMODModule *module = (SECMODModule *)arg;
680 111a38b0 Robert Relyea
681 111a38b0 Robert Relyea
    do {
682 1b902f7d Alon Levy
        /*
683 1b902f7d Alon Levy
         * XXX - the latency value doesn't matter one bit. you only get no
684 1b902f7d Alon Levy
         * blocking (flags |= CKF_DONT_BLOCK) or PKCS11_WAIT_LATENCY (==500),
685 1b902f7d Alon Levy
         * hard coded in coolkey.  And it isn't coolkey's fault - the timeout
686 1b902f7d Alon Levy
         * value we pass get's dropped on the floor before C_WaitForSlotEvent
687 1b902f7d Alon Levy
         * is called.
688 1b902f7d Alon Levy
         */
689 111a38b0 Robert Relyea
        slot = SECMOD_WaitForAnyTokenEvent(module, 0, 500);
690 111a38b0 Robert Relyea
        if (slot == NULL) {
691 1b902f7d Alon Levy
            /* this could be just a no event indication */
692 1b902f7d Alon Levy
            if (PORT_GetError() == SEC_ERROR_NO_EVENT) {
693 1b902f7d Alon Levy
                continue;
694 1b902f7d Alon Levy
            }
695 111a38b0 Robert Relyea
            break;
696 111a38b0 Robert Relyea
        }
697 111a38b0 Robert Relyea
        vreader = vcard_emul_find_vreader_from_slot(slot);
698 111a38b0 Robert Relyea
        if (vreader == NULL) {
699 111a38b0 Robert Relyea
            /* new vreader */
700 111a38b0 Robert Relyea
            vreader_emul = vreader_emul_new(slot, default_card_type,
701 111a38b0 Robert Relyea
                                            default_type_params);
702 111a38b0 Robert Relyea
            vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul,
703 111a38b0 Robert Relyea
                                  vreader_emul_delete);
704 111a38b0 Robert Relyea
            PK11_FreeSlot(slot);
705 111a38b0 Robert Relyea
            slot = NULL;
706 111a38b0 Robert Relyea
            vreader_add_reader(vreader);
707 111a38b0 Robert Relyea
            vreader_free(vreader);
708 111a38b0 Robert Relyea
            continue;
709 111a38b0 Robert Relyea
        }
710 111a38b0 Robert Relyea
        /* card remove/insert */
711 111a38b0 Robert Relyea
        vreader_emul = vreader_get_private(vreader);
712 111a38b0 Robert Relyea
        if (PK11_IsPresent(slot)) {
713 111a38b0 Robert Relyea
            int series = PK11_GetSlotSeries(slot);
714 111a38b0 Robert Relyea
            if (series != vreader_emul->series) {
715 111a38b0 Robert Relyea
                if (vreader_emul->present) {
716 111a38b0 Robert Relyea
                    vreader_insert_card(vreader, NULL);
717 111a38b0 Robert Relyea
                }
718 111a38b0 Robert Relyea
                vcard = vcard_emul_mirror_card(vreader);
719 111a38b0 Robert Relyea
                vreader_insert_card(vreader, vcard);
720 111a38b0 Robert Relyea
                vcard_free(vcard);
721 111a38b0 Robert Relyea
            }
722 111a38b0 Robert Relyea
            vreader_emul->series = series;
723 111a38b0 Robert Relyea
            vreader_emul->present = 1;
724 111a38b0 Robert Relyea
            vreader_free(vreader);
725 111a38b0 Robert Relyea
            PK11_FreeSlot(slot);
726 111a38b0 Robert Relyea
            continue;
727 111a38b0 Robert Relyea
        }
728 111a38b0 Robert Relyea
        if (vreader_emul->present) {
729 111a38b0 Robert Relyea
            vreader_insert_card(vreader, NULL);
730 111a38b0 Robert Relyea
        }
731 111a38b0 Robert Relyea
        vreader_emul->series = 0;
732 111a38b0 Robert Relyea
        vreader_emul->present = 0;
733 111a38b0 Robert Relyea
        PK11_FreeSlot(slot);
734 111a38b0 Robert Relyea
        vreader_free(vreader);
735 111a38b0 Robert Relyea
    } while (1);
736 111a38b0 Robert Relyea
}
737 111a38b0 Robert Relyea
738 111a38b0 Robert Relyea
/* if the card is inserted when we start up, make sure our state is correct */
739 111a38b0 Robert Relyea
static void
740 111a38b0 Robert Relyea
vcard_emul_init_series(VReader *vreader, VCard *vcard)
741 111a38b0 Robert Relyea
{
742 111a38b0 Robert Relyea
    VReaderEmul *vreader_emul = vreader_get_private(vreader);
743 111a38b0 Robert Relyea
    PK11SlotInfo *slot = vreader_emul->slot;
744 111a38b0 Robert Relyea
745 111a38b0 Robert Relyea
    vreader_emul->present = PK11_IsPresent(slot);
746 111a38b0 Robert Relyea
    vreader_emul->series = PK11_GetSlotSeries(slot);
747 111a38b0 Robert Relyea
    if (vreader_emul->present == 0) {
748 111a38b0 Robert Relyea
        vreader_insert_card(vreader, NULL);
749 111a38b0 Robert Relyea
    }
750 111a38b0 Robert Relyea
}
751 111a38b0 Robert Relyea
752 111a38b0 Robert Relyea
/*
753 111a38b0 Robert Relyea
 * each module has a separate wait call, create a thread for each module that
754 111a38b0 Robert Relyea
 * we are using.
755 111a38b0 Robert Relyea
 */
756 111a38b0 Robert Relyea
static void
757 111a38b0 Robert Relyea
vcard_emul_new_event_thread(SECMODModule *module)
758 111a38b0 Robert Relyea
{
759 111a38b0 Robert Relyea
    PR_CreateThread(PR_SYSTEM_THREAD, vcard_emul_event_thread,
760 111a38b0 Robert Relyea
                     module, PR_PRIORITY_HIGH, PR_GLOBAL_THREAD,
761 111a38b0 Robert Relyea
                     PR_UNJOINABLE_THREAD, 0);
762 111a38b0 Robert Relyea
}
763 111a38b0 Robert Relyea
764 111a38b0 Robert Relyea
static const VCardEmulOptions default_options = {
765 111a38b0 Robert Relyea
    .nss_db = NULL,
766 111a38b0 Robert Relyea
    .vreader = NULL,
767 111a38b0 Robert Relyea
    .vreader_count = 0,
768 111a38b0 Robert Relyea
    .hw_card_type = VCARD_EMUL_CAC,
769 111a38b0 Robert Relyea
    .hw_type_params = "",
770 111a38b0 Robert Relyea
    .use_hw = PR_TRUE
771 111a38b0 Robert Relyea
};
772 111a38b0 Robert Relyea
773 111a38b0 Robert Relyea
774 111a38b0 Robert Relyea
/*
775 111a38b0 Robert Relyea
 *  NSS needs the app to supply a password prompt. In our case the only time
776 111a38b0 Robert Relyea
 *  the password is supplied is as part of the Login APDU. The actual password
777 111a38b0 Robert Relyea
 *  is passed in the pw_arg in that case. In all other cases pw_arg should be
778 111a38b0 Robert Relyea
 *  NULL.
779 111a38b0 Robert Relyea
 */
780 111a38b0 Robert Relyea
static char *
781 111a38b0 Robert Relyea
vcard_emul_get_password(PK11SlotInfo *slot, PRBool retries, void *pw_arg)
782 111a38b0 Robert Relyea
{
783 111a38b0 Robert Relyea
    /* if it didn't work the first time, don't keep trying */
784 111a38b0 Robert Relyea
    if (retries) {
785 111a38b0 Robert Relyea
        return NULL;
786 111a38b0 Robert Relyea
    }
787 111a38b0 Robert Relyea
    /* we are looking up a password when we don't have one in hand */
788 111a38b0 Robert Relyea
    if (pw_arg == NULL) {
789 111a38b0 Robert Relyea
        return NULL;
790 111a38b0 Robert Relyea
    }
791 111a38b0 Robert Relyea
    /* TODO: we really should verify that were are using the right slot */
792 111a38b0 Robert Relyea
    return PORT_Strdup(pw_arg);
793 111a38b0 Robert Relyea
}
794 111a38b0 Robert Relyea
795 111a38b0 Robert Relyea
/* Force a card removal even if the card is not physically removed */
796 111a38b0 Robert Relyea
VCardEmulError
797 111a38b0 Robert Relyea
vcard_emul_force_card_remove(VReader *vreader)
798 111a38b0 Robert Relyea
{
799 111a38b0 Robert Relyea
    if (!nss_emul_init || (vreader_card_is_present(vreader) != VREADER_OK)) {
800 111a38b0 Robert Relyea
        return VCARD_EMUL_FAIL; /* card is already removed */
801 111a38b0 Robert Relyea
    }
802 111a38b0 Robert Relyea
803 111a38b0 Robert Relyea
    /* OK, remove it */
804 111a38b0 Robert Relyea
    vreader_insert_card(vreader, NULL);
805 111a38b0 Robert Relyea
    return VCARD_EMUL_OK;
806 111a38b0 Robert Relyea
}
807 111a38b0 Robert Relyea
808 111a38b0 Robert Relyea
/* Re-insert of a card that has been removed by force removal */
809 111a38b0 Robert Relyea
VCardEmulError
810 111a38b0 Robert Relyea
vcard_emul_force_card_insert(VReader *vreader)
811 111a38b0 Robert Relyea
{
812 111a38b0 Robert Relyea
    VReaderEmul *vreader_emul;
813 111a38b0 Robert Relyea
    VCard *vcard;
814 111a38b0 Robert Relyea
815 111a38b0 Robert Relyea
    if (!nss_emul_init || (vreader_card_is_present(vreader) == VREADER_OK)) {
816 111a38b0 Robert Relyea
        return VCARD_EMUL_FAIL; /* card is already removed */
817 111a38b0 Robert Relyea
    }
818 111a38b0 Robert Relyea
    vreader_emul = vreader_get_private(vreader);
819 111a38b0 Robert Relyea
820 111a38b0 Robert Relyea
    /* if it's a softcard, get the saved vcard from the reader emul structure */
821 111a38b0 Robert Relyea
    if (vreader_emul->saved_vcard) {
822 111a38b0 Robert Relyea
        vcard = vcard_reference(vreader_emul->saved_vcard);
823 111a38b0 Robert Relyea
    } else {
824 111a38b0 Robert Relyea
        /* it must be a physical card, rebuild it */
825 111a38b0 Robert Relyea
        if (!PK11_IsPresent(vreader_emul->slot)) {
826 111a38b0 Robert Relyea
            /* physical card has been removed, not way to reinsert it */
827 111a38b0 Robert Relyea
            return VCARD_EMUL_FAIL;
828 111a38b0 Robert Relyea
        }
829 111a38b0 Robert Relyea
        vcard = vcard_emul_mirror_card(vreader);
830 111a38b0 Robert Relyea
    }
831 111a38b0 Robert Relyea
    vreader_insert_card(vreader, vcard);
832 111a38b0 Robert Relyea
    vcard_free(vcard);
833 111a38b0 Robert Relyea
834 111a38b0 Robert Relyea
    return VCARD_EMUL_OK;
835 111a38b0 Robert Relyea
}
836 111a38b0 Robert Relyea
837 111a38b0 Robert Relyea
838 111a38b0 Robert Relyea
static PRBool
839 111a38b0 Robert Relyea
module_has_removable_hw_slots(SECMODModule *mod)
840 111a38b0 Robert Relyea
{
841 111a38b0 Robert Relyea
    int i;
842 111a38b0 Robert Relyea
    PRBool ret = PR_FALSE;
843 111a38b0 Robert Relyea
    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
844 111a38b0 Robert Relyea
845 111a38b0 Robert Relyea
    if (!moduleLock) {
846 111a38b0 Robert Relyea
        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
847 111a38b0 Robert Relyea
        return ret;
848 111a38b0 Robert Relyea
    }
849 111a38b0 Robert Relyea
    SECMOD_GetReadLock(moduleLock);
850 111a38b0 Robert Relyea
    for (i = 0; i < mod->slotCount; i++) {
851 111a38b0 Robert Relyea
        PK11SlotInfo *slot = mod->slots[i];
852 111a38b0 Robert Relyea
        if (PK11_IsRemovable(slot) && PK11_IsHW(slot)) {
853 111a38b0 Robert Relyea
            ret = PR_TRUE;
854 111a38b0 Robert Relyea
            break;
855 111a38b0 Robert Relyea
        }
856 111a38b0 Robert Relyea
    }
857 111a38b0 Robert Relyea
    SECMOD_ReleaseReadLock(moduleLock);
858 111a38b0 Robert Relyea
    return ret;
859 111a38b0 Robert Relyea
}
860 111a38b0 Robert Relyea
861 111a38b0 Robert Relyea
/* Previously we returned FAIL if no readers found. This makes
862 111a38b0 Robert Relyea
 * no sense when using hardware, since there may be no readers connected
863 111a38b0 Robert Relyea
 * at the time vcard_emul_init is called, but they will be properly
864 111a38b0 Robert Relyea
 * recognized later. So Instead return FAIL only if no_hw==1 and no
865 111a38b0 Robert Relyea
 * vcards can be created (indicates error with certificates provided
866 111a38b0 Robert Relyea
 * or db), or if any other higher level error (NSS error, missing coolkey). */
867 111a38b0 Robert Relyea
static int vcard_emul_init_called;
868 111a38b0 Robert Relyea
869 111a38b0 Robert Relyea
VCardEmulError
870 111a38b0 Robert Relyea
vcard_emul_init(const VCardEmulOptions *options)
871 111a38b0 Robert Relyea
{
872 111a38b0 Robert Relyea
    SECStatus rv;
873 111a38b0 Robert Relyea
    PRBool ret, has_readers = PR_FALSE, need_coolkey_module;
874 111a38b0 Robert Relyea
    VReader *vreader;
875 111a38b0 Robert Relyea
    VReaderEmul *vreader_emul;
876 111a38b0 Robert Relyea
    SECMODListLock *module_lock;
877 111a38b0 Robert Relyea
    SECMODModuleList *module_list;
878 111a38b0 Robert Relyea
    SECMODModuleList *mlp;
879 111a38b0 Robert Relyea
    int i;
880 111a38b0 Robert Relyea
881 111a38b0 Robert Relyea
    if (vcard_emul_init_called) {
882 111a38b0 Robert Relyea
        return VCARD_EMUL_INIT_ALREADY_INITED;
883 111a38b0 Robert Relyea
    }
884 111a38b0 Robert Relyea
    vcard_emul_init_called = 1;
885 111a38b0 Robert Relyea
    vreader_init();
886 111a38b0 Robert Relyea
    vevent_queue_init();
887 111a38b0 Robert Relyea
888 111a38b0 Robert Relyea
    if (options == NULL) {
889 111a38b0 Robert Relyea
        options = &default_options;
890 111a38b0 Robert Relyea
    }
891 111a38b0 Robert Relyea
892 111a38b0 Robert Relyea
    /* first initialize NSS */
893 111a38b0 Robert Relyea
    if (options->nss_db) {
894 111a38b0 Robert Relyea
        rv = NSS_Init(options->nss_db);
895 111a38b0 Robert Relyea
    } else {
896 111a38b0 Robert Relyea
        rv = NSS_Init("sql:/etc/pki/nssdb");
897 111a38b0 Robert Relyea
    }
898 111a38b0 Robert Relyea
    if (rv != SECSuccess) {
899 111a38b0 Robert Relyea
        return VCARD_EMUL_FAIL;
900 111a38b0 Robert Relyea
    }
901 111a38b0 Robert Relyea
    /* Set password callback function */
902 111a38b0 Robert Relyea
    PK11_SetPasswordFunc(vcard_emul_get_password);
903 111a38b0 Robert Relyea
904 111a38b0 Robert Relyea
    /* set up soft cards emulated by software certs rather than physical cards
905 111a38b0 Robert Relyea
     * */
906 111a38b0 Robert Relyea
    for (i = 0; i < options->vreader_count; i++) {
907 111a38b0 Robert Relyea
        int j;
908 111a38b0 Robert Relyea
        int cert_count;
909 111a38b0 Robert Relyea
        unsigned char **certs;
910 111a38b0 Robert Relyea
        int *cert_len;
911 111a38b0 Robert Relyea
        VCardKey **keys;
912 111a38b0 Robert Relyea
        PK11SlotInfo *slot;
913 111a38b0 Robert Relyea
914 111a38b0 Robert Relyea
        slot = PK11_FindSlotByName(options->vreader[i].name);
915 111a38b0 Robert Relyea
        if (slot == NULL) {
916 111a38b0 Robert Relyea
            continue;
917 111a38b0 Robert Relyea
        }
918 111a38b0 Robert Relyea
        vreader_emul = vreader_emul_new(slot, options->vreader[i].card_type,
919 111a38b0 Robert Relyea
                                        options->vreader[i].type_params);
920 111a38b0 Robert Relyea
        vreader = vreader_new(options->vreader[i].vname, vreader_emul,
921 111a38b0 Robert Relyea
                              vreader_emul_delete);
922 111a38b0 Robert Relyea
        vreader_add_reader(vreader);
923 111a38b0 Robert Relyea
        cert_count = options->vreader[i].cert_count;
924 111a38b0 Robert Relyea
925 111a38b0 Robert Relyea
        ret = vcard_emul_alloc_arrays(&certs, &cert_len, &keys,
926 111a38b0 Robert Relyea
                                      options->vreader[i].cert_count);
927 111a38b0 Robert Relyea
        if (ret == PR_FALSE) {
928 111a38b0 Robert Relyea
            continue;
929 111a38b0 Robert Relyea
        }
930 111a38b0 Robert Relyea
        cert_count = 0;
931 111a38b0 Robert Relyea
        for (j = 0; j < options->vreader[i].cert_count; j++) {
932 111a38b0 Robert Relyea
            /* we should have a better way of identifying certs than by
933 111a38b0 Robert Relyea
             * nickname here */
934 111a38b0 Robert Relyea
            CERTCertificate *cert = PK11_FindCertFromNickname(
935 111a38b0 Robert Relyea
                                        options->vreader[i].cert_name[j],
936 111a38b0 Robert Relyea
                                        NULL);
937 111a38b0 Robert Relyea
            if (cert == NULL) {
938 111a38b0 Robert Relyea
                continue;
939 111a38b0 Robert Relyea
            }
940 111a38b0 Robert Relyea
            certs[cert_count] = cert->derCert.data;
941 111a38b0 Robert Relyea
            cert_len[cert_count] = cert->derCert.len;
942 111a38b0 Robert Relyea
            keys[cert_count] = vcard_emul_make_key(slot, cert);
943 111a38b0 Robert Relyea
            /* this is safe because the key is still holding a cert reference */
944 111a38b0 Robert Relyea
            CERT_DestroyCertificate(cert);
945 111a38b0 Robert Relyea
            cert_count++;
946 111a38b0 Robert Relyea
        }
947 111a38b0 Robert Relyea
        if (cert_count) {
948 111a38b0 Robert Relyea
            VCard *vcard = vcard_emul_make_card(vreader, certs, cert_len,
949 111a38b0 Robert Relyea
                                                keys, cert_count);
950 111a38b0 Robert Relyea
            vreader_insert_card(vreader, vcard);
951 111a38b0 Robert Relyea
            vcard_emul_init_series(vreader, vcard);
952 111a38b0 Robert Relyea
            /* allow insertion and removal of soft cards */
953 111a38b0 Robert Relyea
            vreader_emul->saved_vcard = vcard_reference(vcard);
954 111a38b0 Robert Relyea
            vcard_free(vcard);
955 111a38b0 Robert Relyea
            vreader_free(vreader);
956 111a38b0 Robert Relyea
            has_readers = PR_TRUE;
957 111a38b0 Robert Relyea
        }
958 7267c094 Anthony Liguori
        g_free(certs);
959 7267c094 Anthony Liguori
        g_free(cert_len);
960 7267c094 Anthony Liguori
        g_free(keys);
961 111a38b0 Robert Relyea
    }
962 111a38b0 Robert Relyea
963 111a38b0 Robert Relyea
    /* if we aren't suppose to use hw, skip looking up hardware tokens */
964 111a38b0 Robert Relyea
    if (!options->use_hw) {
965 111a38b0 Robert Relyea
        nss_emul_init = has_readers;
966 111a38b0 Robert Relyea
        return has_readers ? VCARD_EMUL_OK : VCARD_EMUL_FAIL;
967 111a38b0 Robert Relyea
    }
968 111a38b0 Robert Relyea
969 111a38b0 Robert Relyea
    /* make sure we have some PKCS #11 module loaded */
970 111a38b0 Robert Relyea
    module_lock = SECMOD_GetDefaultModuleListLock();
971 111a38b0 Robert Relyea
    module_list = SECMOD_GetDefaultModuleList();
972 111a38b0 Robert Relyea
    need_coolkey_module = !has_readers;
973 111a38b0 Robert Relyea
    SECMOD_GetReadLock(module_lock);
974 111a38b0 Robert Relyea
    for (mlp = module_list; mlp; mlp = mlp->next) {
975 111a38b0 Robert Relyea
        SECMODModule *module = mlp->module;
976 111a38b0 Robert Relyea
        if (module_has_removable_hw_slots(module)) {
977 111a38b0 Robert Relyea
            need_coolkey_module = PR_FALSE;
978 111a38b0 Robert Relyea
            break;
979 111a38b0 Robert Relyea
        }
980 111a38b0 Robert Relyea
    }
981 111a38b0 Robert Relyea
    SECMOD_ReleaseReadLock(module_lock);
982 111a38b0 Robert Relyea
983 111a38b0 Robert Relyea
    if (need_coolkey_module) {
984 111a38b0 Robert Relyea
        SECMODModule *module;
985 111a38b0 Robert Relyea
        module = SECMOD_LoadUserModule(
986 111a38b0 Robert Relyea
                    (char *)"library=libcoolkeypk11.so name=Coolkey",
987 111a38b0 Robert Relyea
                    NULL, PR_FALSE);
988 111a38b0 Robert Relyea
        if (module == NULL) {
989 111a38b0 Robert Relyea
            return VCARD_EMUL_FAIL;
990 111a38b0 Robert Relyea
        }
991 111a38b0 Robert Relyea
        SECMOD_DestroyModule(module); /* free our reference, Module will still
992 111a38b0 Robert Relyea
                                       * be on the list.
993 111a38b0 Robert Relyea
                                       * until we destroy it */
994 111a38b0 Robert Relyea
    }
995 111a38b0 Robert Relyea
996 111a38b0 Robert Relyea
    /* now examine all the slots, finding which should be readers */
997 111a38b0 Robert Relyea
    /* We should control this with options. For now we mirror out any
998 111a38b0 Robert Relyea
     * removable hardware slot */
999 111a38b0 Robert Relyea
    default_card_type = options->hw_card_type;
1000 111a38b0 Robert Relyea
    default_type_params = strdup(options->hw_type_params);
1001 111a38b0 Robert Relyea
1002 111a38b0 Robert Relyea
    SECMOD_GetReadLock(module_lock);
1003 111a38b0 Robert Relyea
    for (mlp = module_list; mlp; mlp = mlp->next) {
1004 111a38b0 Robert Relyea
        SECMODModule *module = mlp->module;
1005 111a38b0 Robert Relyea
1006 4e339882 Alon Levy
        /* Ignore the internal module */
1007 4e339882 Alon Levy
        if (module == NULL || module == SECMOD_GetInternalModule()) {
1008 4e339882 Alon Levy
            continue;
1009 111a38b0 Robert Relyea
        }
1010 111a38b0 Robert Relyea
1011 111a38b0 Robert Relyea
        for (i = 0; i < module->slotCount; i++) {
1012 111a38b0 Robert Relyea
            PK11SlotInfo *slot = module->slots[i];
1013 111a38b0 Robert Relyea
1014 111a38b0 Robert Relyea
            /* only map removable HW slots */
1015 111a38b0 Robert Relyea
            if (slot == NULL || !PK11_IsRemovable(slot) || !PK11_IsHW(slot)) {
1016 111a38b0 Robert Relyea
                continue;
1017 111a38b0 Robert Relyea
            }
1018 6f06f178 Alon Levy
            if (strcmp("E-Gate 0 0", PK11_GetSlotName(slot)) == 0) {
1019 6f06f178 Alon Levy
                /*
1020 6f06f178 Alon Levy
                 * coolkey <= 1.1.0-20 emulates this reader if it can't find
1021 6f06f178 Alon Levy
                 * any hardware readers. This causes problems, warn user of
1022 6f06f178 Alon Levy
                 * problems.
1023 6f06f178 Alon Levy
                 */
1024 6f06f178 Alon Levy
                fprintf(stderr, "known bad coolkey version - see "
1025 6f06f178 Alon Levy
                        "https://bugzilla.redhat.com/show_bug.cgi?id=802435\n");
1026 6f06f178 Alon Levy
                continue;
1027 6f06f178 Alon Levy
            }
1028 111a38b0 Robert Relyea
            vreader_emul = vreader_emul_new(slot, options->hw_card_type,
1029 111a38b0 Robert Relyea
                                            options->hw_type_params);
1030 111a38b0 Robert Relyea
            vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul,
1031 111a38b0 Robert Relyea
                                  vreader_emul_delete);
1032 111a38b0 Robert Relyea
            vreader_add_reader(vreader);
1033 111a38b0 Robert Relyea
1034 111a38b0 Robert Relyea
            if (PK11_IsPresent(slot)) {
1035 111a38b0 Robert Relyea
                VCard *vcard;
1036 111a38b0 Robert Relyea
                vcard = vcard_emul_mirror_card(vreader);
1037 111a38b0 Robert Relyea
                vreader_insert_card(vreader, vcard);
1038 111a38b0 Robert Relyea
                vcard_emul_init_series(vreader, vcard);
1039 111a38b0 Robert Relyea
                vcard_free(vcard);
1040 111a38b0 Robert Relyea
            }
1041 111a38b0 Robert Relyea
        }
1042 4e339882 Alon Levy
        vcard_emul_new_event_thread(module);
1043 111a38b0 Robert Relyea
    }
1044 111a38b0 Robert Relyea
    SECMOD_ReleaseReadLock(module_lock);
1045 4e339882 Alon Levy
    nss_emul_init = PR_TRUE;
1046 111a38b0 Robert Relyea
1047 111a38b0 Robert Relyea
    return VCARD_EMUL_OK;
1048 111a38b0 Robert Relyea
}
1049 111a38b0 Robert Relyea
1050 111a38b0 Robert Relyea
/* Recreate card insert events for all readers (user should
1051 111a38b0 Robert Relyea
 * deduce implied reader insert. perhaps do a reader insert as well?)
1052 111a38b0 Robert Relyea
 */
1053 111a38b0 Robert Relyea
void
1054 111a38b0 Robert Relyea
vcard_emul_replay_insertion_events(void)
1055 111a38b0 Robert Relyea
{
1056 111a38b0 Robert Relyea
    VReaderListEntry *current_entry;
1057 111a38b0 Robert Relyea
    VReaderListEntry *next_entry = NULL;
1058 111a38b0 Robert Relyea
    VReaderList *list = vreader_get_reader_list();
1059 111a38b0 Robert Relyea
1060 111a38b0 Robert Relyea
    for (current_entry = vreader_list_get_first(list); current_entry;
1061 111a38b0 Robert Relyea
            current_entry = next_entry) {
1062 111a38b0 Robert Relyea
        VReader *vreader = vreader_list_get_reader(current_entry);
1063 111a38b0 Robert Relyea
        next_entry = vreader_list_get_next(current_entry);
1064 111a38b0 Robert Relyea
        vreader_queue_card_event(vreader);
1065 111a38b0 Robert Relyea
    }
1066 111a38b0 Robert Relyea
}
1067 111a38b0 Robert Relyea
1068 111a38b0 Robert Relyea
/*
1069 111a38b0 Robert Relyea
 *  Silly little functions to help parsing our argument string
1070 111a38b0 Robert Relyea
 */
1071 111a38b0 Robert Relyea
static int
1072 111a38b0 Robert Relyea
count_tokens(const char *str, char token, char token_end)
1073 111a38b0 Robert Relyea
{
1074 111a38b0 Robert Relyea
    int count = 0;
1075 111a38b0 Robert Relyea
1076 111a38b0 Robert Relyea
    for (; *str; str++) {
1077 111a38b0 Robert Relyea
        if (*str == token) {
1078 111a38b0 Robert Relyea
            count++;
1079 111a38b0 Robert Relyea
        }
1080 111a38b0 Robert Relyea
        if (*str == token_end) {
1081 111a38b0 Robert Relyea
            break;
1082 111a38b0 Robert Relyea
        }
1083 111a38b0 Robert Relyea
    }
1084 111a38b0 Robert Relyea
    return count;
1085 111a38b0 Robert Relyea
}
1086 111a38b0 Robert Relyea
1087 111a38b0 Robert Relyea
static const char *
1088 111a38b0 Robert Relyea
strip(const char *str)
1089 111a38b0 Robert Relyea
{
1090 685ff50f Alon Levy
    for (; *str && isspace(*str); str++) {
1091 111a38b0 Robert Relyea
    }
1092 111a38b0 Robert Relyea
    return str;
1093 111a38b0 Robert Relyea
}
1094 111a38b0 Robert Relyea
1095 111a38b0 Robert Relyea
static const char *
1096 111a38b0 Robert Relyea
find_blank(const char *str)
1097 111a38b0 Robert Relyea
{
1098 685ff50f Alon Levy
    for (; *str && !isspace(*str); str++) {
1099 111a38b0 Robert Relyea
    }
1100 111a38b0 Robert Relyea
    return str;
1101 111a38b0 Robert Relyea
}
1102 111a38b0 Robert Relyea
1103 111a38b0 Robert Relyea
1104 111a38b0 Robert Relyea
/*
1105 111a38b0 Robert Relyea
 *  We really want to use some existing argument parsing library here. That
1106 fc27eefe Stefan Weil
 *  would give us a consistent look */
1107 111a38b0 Robert Relyea
static VCardEmulOptions options;
1108 111a38b0 Robert Relyea
#define READER_STEP 4
1109 111a38b0 Robert Relyea
1110 d246b3cf Christophe Fergeau
/* Expects "args" to be at the beginning of a token (ie right after the ','
1111 d246b3cf Christophe Fergeau
 * ending the previous token), and puts the next token start in "token",
1112 d246b3cf Christophe Fergeau
 * and its length in "token_length". "token" will not be nul-terminated.
1113 d246b3cf Christophe Fergeau
 * After calling the macro, "args" will be advanced to the beginning of
1114 d246b3cf Christophe Fergeau
 * the next token.
1115 d246b3cf Christophe Fergeau
 * This macro may call continue or break.
1116 d246b3cf Christophe Fergeau
 */
1117 d246b3cf Christophe Fergeau
#define NEXT_TOKEN(token) \
1118 d246b3cf Christophe Fergeau
            (token) = args; \
1119 d246b3cf Christophe Fergeau
            args = strpbrk(args, ",)"); \
1120 d246b3cf Christophe Fergeau
            if (*args == 0) { \
1121 d246b3cf Christophe Fergeau
                break; \
1122 d246b3cf Christophe Fergeau
            } \
1123 d246b3cf Christophe Fergeau
            if (*args == ')') { \
1124 d246b3cf Christophe Fergeau
                args++; \
1125 d246b3cf Christophe Fergeau
                continue; \
1126 d246b3cf Christophe Fergeau
            } \
1127 d246b3cf Christophe Fergeau
            (token##_length) = args - (token); \
1128 d246b3cf Christophe Fergeau
            args = strip(args+1);
1129 d246b3cf Christophe Fergeau
1130 111a38b0 Robert Relyea
VCardEmulOptions *
1131 111a38b0 Robert Relyea
vcard_emul_options(const char *args)
1132 111a38b0 Robert Relyea
{
1133 111a38b0 Robert Relyea
    int reader_count = 0;
1134 111a38b0 Robert Relyea
    VCardEmulOptions *opts;
1135 111a38b0 Robert Relyea
1136 111a38b0 Robert Relyea
    /* Allow the future use of allocating the options structure on the fly */
1137 111a38b0 Robert Relyea
    memcpy(&options, &default_options, sizeof(options));
1138 111a38b0 Robert Relyea
    opts = &options;
1139 111a38b0 Robert Relyea
1140 111a38b0 Robert Relyea
    do {
1141 111a38b0 Robert Relyea
        args = strip(args); /* strip off the leading spaces */
1142 111a38b0 Robert Relyea
        if (*args == ',') {
1143 111a38b0 Robert Relyea
            continue;
1144 111a38b0 Robert Relyea
        }
1145 111a38b0 Robert Relyea
        /* soft=(slot_name,virt_name,emul_type,emul_flags,cert_1, (no eol)
1146 111a38b0 Robert Relyea
         *       cert_2,cert_3...) */
1147 111a38b0 Robert Relyea
        if (strncmp(args, "soft=", 5) == 0) {
1148 111a38b0 Robert Relyea
            const char *name;
1149 a5aa842a Christophe Fergeau
            size_t name_length;
1150 111a38b0 Robert Relyea
            const char *vname;
1151 a5aa842a Christophe Fergeau
            size_t vname_length;
1152 111a38b0 Robert Relyea
            const char *type_params;
1153 a5aa842a Christophe Fergeau
            size_t type_params_length;
1154 a5aa842a Christophe Fergeau
            char type_str[100];
1155 111a38b0 Robert Relyea
            VCardEmulType type;
1156 a5aa842a Christophe Fergeau
            int count, i;
1157 111a38b0 Robert Relyea
            VirtualReaderOptions *vreaderOpt = NULL;
1158 111a38b0 Robert Relyea
1159 111a38b0 Robert Relyea
            args = strip(args + 5);
1160 111a38b0 Robert Relyea
            if (*args != '(') {
1161 111a38b0 Robert Relyea
                continue;
1162 111a38b0 Robert Relyea
            }
1163 a5aa842a Christophe Fergeau
            args = strip(args+1);
1164 a5aa842a Christophe Fergeau
1165 d246b3cf Christophe Fergeau
            NEXT_TOKEN(name)
1166 d246b3cf Christophe Fergeau
            NEXT_TOKEN(vname)
1167 d246b3cf Christophe Fergeau
            NEXT_TOKEN(type_params)
1168 a5aa842a Christophe Fergeau
            type_params_length = MIN(type_params_length, sizeof(type_str)-1);
1169 2e679780 Jim Meyering
            pstrcpy(type_str, type_params_length, type_params);
1170 a5aa842a Christophe Fergeau
            type = vcard_emul_type_from_string(type_str);
1171 a5aa842a Christophe Fergeau
1172 d246b3cf Christophe Fergeau
            NEXT_TOKEN(type_params)
1173 a5aa842a Christophe Fergeau
1174 111a38b0 Robert Relyea
            if (*args == 0) {
1175 111a38b0 Robert Relyea
                break;
1176 111a38b0 Robert Relyea
            }
1177 111a38b0 Robert Relyea
1178 111a38b0 Robert Relyea
            if (opts->vreader_count >= reader_count) {
1179 111a38b0 Robert Relyea
                reader_count += READER_STEP;
1180 111a38b0 Robert Relyea
                vreaderOpt = realloc(opts->vreader,
1181 111a38b0 Robert Relyea
                                reader_count * sizeof(*vreaderOpt));
1182 111a38b0 Robert Relyea
                if (vreaderOpt == NULL) {
1183 111a38b0 Robert Relyea
                    return opts; /* we're done */
1184 111a38b0 Robert Relyea
                }
1185 111a38b0 Robert Relyea
            }
1186 111a38b0 Robert Relyea
            opts->vreader = vreaderOpt;
1187 111a38b0 Robert Relyea
            vreaderOpt = &vreaderOpt[opts->vreader_count];
1188 7267c094 Anthony Liguori
            vreaderOpt->name = g_strndup(name, name_length);
1189 7267c094 Anthony Liguori
            vreaderOpt->vname = g_strndup(vname, vname_length);
1190 111a38b0 Robert Relyea
            vreaderOpt->card_type = type;
1191 111a38b0 Robert Relyea
            vreaderOpt->type_params =
1192 7267c094 Anthony Liguori
                g_strndup(type_params, type_params_length);
1193 a5aa842a Christophe Fergeau
            count = count_tokens(args, ',', ')') + 1;
1194 111a38b0 Robert Relyea
            vreaderOpt->cert_count = count;
1195 7267c094 Anthony Liguori
            vreaderOpt->cert_name = (char **)g_malloc(count*sizeof(char *));
1196 111a38b0 Robert Relyea
            for (i = 0; i < count; i++) {
1197 a5aa842a Christophe Fergeau
                const char *cert = args;
1198 a5aa842a Christophe Fergeau
                args = strpbrk(args, ",)");
1199 7267c094 Anthony Liguori
                vreaderOpt->cert_name[i] = g_strndup(cert, args - cert);
1200 a5aa842a Christophe Fergeau
                args = strip(args+1);
1201 111a38b0 Robert Relyea
            }
1202 111a38b0 Robert Relyea
            if (*args == ')') {
1203 111a38b0 Robert Relyea
                args++;
1204 111a38b0 Robert Relyea
            }
1205 111a38b0 Robert Relyea
            opts->vreader_count++;
1206 111a38b0 Robert Relyea
        /* use_hw= */
1207 111a38b0 Robert Relyea
        } else if (strncmp(args, "use_hw=", 7) == 0) {
1208 111a38b0 Robert Relyea
            args = strip(args+7);
1209 111a38b0 Robert Relyea
            if (*args == '0' || *args == 'N' || *args == 'n' || *args == 'F') {
1210 111a38b0 Robert Relyea
                opts->use_hw = PR_FALSE;
1211 111a38b0 Robert Relyea
            } else {
1212 111a38b0 Robert Relyea
                opts->use_hw = PR_TRUE;
1213 111a38b0 Robert Relyea
            }
1214 111a38b0 Robert Relyea
            args = find_blank(args);
1215 111a38b0 Robert Relyea
        /* hw_type= */
1216 111a38b0 Robert Relyea
        } else if (strncmp(args, "hw_type=", 8) == 0) {
1217 111a38b0 Robert Relyea
            args = strip(args+8);
1218 111a38b0 Robert Relyea
            opts->hw_card_type = vcard_emul_type_from_string(args);
1219 111a38b0 Robert Relyea
            args = find_blank(args);
1220 111a38b0 Robert Relyea
        /* hw_params= */
1221 111a38b0 Robert Relyea
        } else if (strncmp(args, "hw_params=", 10) == 0) {
1222 111a38b0 Robert Relyea
            const char *params;
1223 111a38b0 Robert Relyea
            args = strip(args+10);
1224 111a38b0 Robert Relyea
            params = args;
1225 111a38b0 Robert Relyea
            args = find_blank(args);
1226 7267c094 Anthony Liguori
            opts->hw_type_params = g_strndup(params, args-params);
1227 111a38b0 Robert Relyea
        /* db="/data/base/path" */
1228 111a38b0 Robert Relyea
        } else if (strncmp(args, "db=", 3) == 0) {
1229 111a38b0 Robert Relyea
            const char *db;
1230 111a38b0 Robert Relyea
            args = strip(args+3);
1231 111a38b0 Robert Relyea
            if (*args != '"') {
1232 111a38b0 Robert Relyea
                continue;
1233 111a38b0 Robert Relyea
            }
1234 111a38b0 Robert Relyea
            args++;
1235 111a38b0 Robert Relyea
            db = args;
1236 111a38b0 Robert Relyea
            args = strpbrk(args, "\"\n");
1237 7267c094 Anthony Liguori
            opts->nss_db = g_strndup(db, args-db);
1238 111a38b0 Robert Relyea
            if (*args != 0) {
1239 111a38b0 Robert Relyea
                args++;
1240 111a38b0 Robert Relyea
            }
1241 111a38b0 Robert Relyea
        } else {
1242 111a38b0 Robert Relyea
            args = find_blank(args);
1243 111a38b0 Robert Relyea
        }
1244 111a38b0 Robert Relyea
    } while (*args != 0);
1245 111a38b0 Robert Relyea
1246 111a38b0 Robert Relyea
    return opts;
1247 111a38b0 Robert Relyea
}
1248 111a38b0 Robert Relyea
1249 111a38b0 Robert Relyea
void
1250 111a38b0 Robert Relyea
vcard_emul_usage(void)
1251 111a38b0 Robert Relyea
{
1252 111a38b0 Robert Relyea
   fprintf(stderr,
1253 111a38b0 Robert Relyea
"emul args: comma separated list of the following arguments\n"
1254 111a38b0 Robert Relyea
" db={nss_database}               (default sql:/etc/pki/nssdb)\n"
1255 111a38b0 Robert Relyea
" use_hw=[yes|no]                 (default yes)\n"
1256 111a38b0 Robert Relyea
" hw_type={card_type_to_emulate}  (default CAC)\n"
1257 111a38b0 Robert Relyea
" hw_param={param_for_card}       (default \"\")\n"
1258 111a38b0 Robert Relyea
" soft=({slot_name},{vreader_name},{card_type_to_emulate},{params_for_card},\n"
1259 111a38b0 Robert Relyea
"       {cert1},{cert2},{cert3}    (default none)\n"
1260 111a38b0 Robert Relyea
"\n"
1261 111a38b0 Robert Relyea
"  {nss_database}          The location of the NSS cert & key database\n"
1262 111a38b0 Robert Relyea
"  {card_type_to_emulate}  What card interface to present to the guest\n"
1263 111a38b0 Robert Relyea
"  {param_for_card}        Card interface specific parameters\n"
1264 111a38b0 Robert Relyea
"  {slot_name}             NSS slot that contains the certs\n"
1265 cba919da Dong Xu Wang
"  {vreader_name}          Virtual reader name to present to the guest\n"
1266 111a38b0 Robert Relyea
"  {certN}                 Nickname of the certificate n on the virtual card\n"
1267 111a38b0 Robert Relyea
"\n"
1268 111a38b0 Robert Relyea
"These parameters come as a single string separated by blanks or newlines."
1269 111a38b0 Robert Relyea
"\n"
1270 111a38b0 Robert Relyea
"Unless use_hw is set to no, all tokens that look like removable hardware\n"
1271 111a38b0 Robert Relyea
"tokens will be presented to the guest using the emulator specified by\n"
1272 111a38b0 Robert Relyea
"hw_type, and parameters of hw_param.\n"
1273 111a38b0 Robert Relyea
"\n"
1274 111a38b0 Robert Relyea
"If more one or more soft= parameters are specified, these readers will be\n"
1275 111a38b0 Robert Relyea
"presented to the guest\n");
1276 111a38b0 Robert Relyea
}