Esempio n. 1
0
static int list_readers(sc_context_t *ctx)
{
    char card_atr[0x3e];
    sc_card_t *card;
    sc_reader_t *reader;
	size_t i, rcount = sc_ctx_get_reader_count(ctx);
	
	if (rcount == 0) {
		printf("No smart card readers found.\n");
		return 0;
	}
    printf("%-4s %-7s %s\n", "Nr.", "Driver", "Smart Card Reader");
	for (i = 0; i < rcount; i++) {
		reader = sc_ctx_get_reader(ctx, i);
        memset(card_atr, '\0', sizeof card_atr);
        if (sc_detect_card_presence(reader) & SC_READER_CARD_PRESENT) {
            if (sc_connect_card(reader, &card) == SC_SUCCESS) {
                sc_bin_to_hex(card->atr.value, card->atr.len,
                        card_atr, sizeof card_atr, ':');
            }
            sc_disconnect_card(card);
        } else {
            strncpy(card_atr, "[no card present]", sizeof card_atr);
        }
        printf("%-4d %-7s %s\n", i, reader->driver->short_name, reader->name);
        printf("             ATR: %s\n", card_atr);
	}

	return 0;
}
Esempio n. 2
0
File: slot.c Progetto: llogar/OpenSC
CK_RV
card_detect_all(void)
{
	unsigned int i;

	sc_log(context, "Detect all cards");
	/* Detect cards in all initialized readers */
	for (i=0; i< sc_ctx_get_reader_count(context); i++) {
		sc_reader_t *reader = sc_ctx_get_reader(context, i);
		if (reader->flags & SC_READER_REMOVED) {
			struct sc_pkcs11_slot *slot;
			card_removed(reader);
			while ((slot = reader_get_slot(reader))) {
				empty_slot(slot);
			}
			_sc_delete_reader(context, reader);
			i--;
		} else {
			if (!reader_get_slot(reader))
				initialize_reader(reader);
			else
				card_detect(sc_ctx_get_reader(context, i));
		}
	}
	sc_log(context, "All cards detected");
	return CKR_OK;
}
Esempio n. 3
0
CK_RV card_detect_all(void) {
	 unsigned int i;

	 /* Detect cards in all initialized readers */
	 for (i=0; i< sc_ctx_get_reader_count(context); i++) {
		 sc_reader_t *reader = sc_ctx_get_reader(context, i);
		 if (!reader_get_slot(reader))
			 initialize_reader(reader);
		 card_detect(sc_ctx_get_reader(context, i));
	 }
	 return CKR_OK;			
}
Esempio n. 4
0
int initialize(int reader_id, int verbose,
        sc_context_t **ctx, sc_reader_t **reader)
{
    unsigned int i, reader_count;

    if (!ctx || !reader)
        return SC_ERROR_INVALID_ARGUMENTS;

    int r = sc_establish_context(ctx, "");
    if (r < 0 || !*ctx) {
        fprintf(stderr, "Failed to create initial context: %s", sc_strerror(r));
        return r;
    }

    (*ctx)->debug = verbose;
	(*ctx)->enable_default_driver = 1;

    reader_count = sc_ctx_get_reader_count(*ctx);

    if (reader_count == 0) {
        sc_debug(*ctx, SC_LOG_DEBUG_NORMAL, "No reader not found.\n");
        return SC_ERROR_NO_READERS_FOUND;
    }

    if (reader_id < 0) {
        /* Automatically try to skip to a reader with a card if reader not specified */
        for (i = 0; i < reader_count; i++) {
            *reader = sc_ctx_get_reader(*ctx, i);
            if (sc_detect_card_presence(*reader) & SC_READER_CARD_PRESENT) {
                reader_id = i;
                sc_debug(*ctx, SC_LOG_DEBUG_NORMAL, "Using the first reader"
                        " with a card: %s", (*reader)->name);
                break;
            }
        }
        if (reader_id >= reader_count) {
            sc_debug(*ctx, SC_LOG_DEBUG_NORMAL, "No card found, using the first reader.");
            reader_id = 0;
        }
    }

    if (reader_id >= reader_count) {
        sc_debug(*ctx, SC_LOG_DEBUG_NORMAL, "Invalid reader number "
                "(%d), only %d available.\n", reader_id, reader_count);
        return SC_ERROR_NO_READERS_FOUND;
    }

    *reader = sc_ctx_get_reader(*ctx, reader_id);

    return SC_SUCCESS;
}
Esempio n. 5
0
CK_RV C_Finalize(CK_VOID_PTR pReserved)
{
	int i;
	void *p;
	sc_pkcs11_slot_t *slot;
	CK_RV rv;

	if (pReserved != NULL_PTR)
		return CKR_ARGUMENTS_BAD;

#if !defined(_WIN32)
	sc_notify_close();
#endif

	if (context == NULL)
		return CKR_CRYPTOKI_NOT_INITIALIZED;

	rv = sc_pkcs11_lock();
	if (rv != CKR_OK)
		return rv;

	sc_log(context, "C_Finalize()");

	/* cancel pending calls */
	in_finalize = 1;
	sc_cancel(context);
	/* remove all cards from readers */
	for (i=0; i < (int)sc_ctx_get_reader_count(context); i++)
		card_removed(sc_ctx_get_reader(context, i));

	while ((p = list_fetch(&sessions)))
		free(p);
	list_destroy(&sessions);

	while ((slot = list_fetch(&virtual_slots))) {
		list_destroy(&slot->objects);
		list_destroy(&slot->logins);
		free(slot);
	}
	list_destroy(&virtual_slots);

	sc_release_context(context);
	context = NULL;

	/* Release and destroy the mutex */
	sc_pkcs11_free_lock();

	return rv;
}
static int list_readers(void)
{
	unsigned int i, rcount = sc_ctx_get_reader_count(ctx);
	
	if (rcount == 0) {
		printf("No readers configured!\n");
		return 0;
	}
	printf("Readers known about:\n");
	printf("Nr.    Driver     Name\n");
	for (i = 0; i < rcount; i++) {
		sc_reader_t *screader = sc_ctx_get_reader(ctx, i);
		printf("%-7d%-11s%s\n", i, screader->driver->short_name,
		       screader->name);
	}
	return 0;
}
Esempio n. 7
0
CK_RV C_Initialize(CK_VOID_PTR pInitArgs)
{
	CK_RV rv;
#if !defined(_WIN32)
	pid_t current_pid = getpid();
#endif
	int rc;
	unsigned int i;
	sc_context_param_t ctx_opts;

#if !defined(_WIN32)
	/* Handle fork() exception */
	if (current_pid != initialized_pid) {
		if (context)
			context->flags |= SC_CTX_FLAG_TERMINATE;
		C_Finalize(NULL_PTR);
	}
	initialized_pid = current_pid;
	in_finalize = 0;
#endif

	if (context != NULL) {
		sc_log(context, "C_Initialize(): Cryptoki already initialized\n");
		return CKR_CRYPTOKI_ALREADY_INITIALIZED;
	}

	rv = sc_pkcs11_init_lock((CK_C_INITIALIZE_ARGS_PTR) pInitArgs);
	if (rv != CKR_OK)
		goto out;

	/* set context options */
	memset(&ctx_opts, 0, sizeof(sc_context_param_t));
	ctx_opts.ver        = 0;
	ctx_opts.app_name   = MODULE_APP_NAME;
	ctx_opts.thread_ctx = &sc_thread_ctx;

	rc = sc_context_create(&context, &ctx_opts);
	if (rc != SC_SUCCESS) {
		rv = CKR_GENERAL_ERROR;
		goto out;
	}

	/* Load configuration */
	load_pkcs11_parameters(&sc_pkcs11_conf, context);

	/* List of sessions */
	list_init(&sessions);
	list_attributes_seeker(&sessions, session_list_seeker);

	/* List of slots */
	list_init(&virtual_slots);
	list_attributes_seeker(&virtual_slots, slot_list_seeker);

	/* Create a slot for a future "PnP" stuff. */
	if (sc_pkcs11_conf.plug_and_play) {
		create_slot(NULL);
	}

	/* Create slots for readers found on initialization, only if in 2.11 mode */
	if (!sc_pkcs11_conf.plug_and_play) {
		for (i=0; i<sc_ctx_get_reader_count(context); i++) {
			initialize_reader(sc_ctx_get_reader(context, i));
		}
	}

out:
	if (context != NULL)
		sc_log(context, "C_Initialize() = %s", lookup_enum ( RV_T, rv ));

	if (rv != CKR_OK) {
		if (context != NULL) {
			sc_release_context(context);
			context = NULL;
		}
		/* Release and destroy the mutex */
		sc_pkcs11_free_lock();
	}

	return rv;
}
Esempio n. 8
0
int sc_test_init(int *argc, char *argv[])
{
	char	*opt_driver = NULL, *app_name;
	int	opt_debug = 0, opt_reader = -1;
	int	i, c, rc;
	sc_context_param_t ctx_param;

	if  ((app_name = strrchr(argv[0], '/')) != NULL)
		app_name++;
	else
		app_name = argv[0];

	while ((c = getopt_long(*argc, argv, "r:c:d", options, NULL)) != -1) {
		switch (c) {
		case 'r':
			opt_reader = atoi(optarg);
			break;
		case 'c':
			opt_driver = optarg;
			break;
		case 'd':
			opt_debug++;
			break;
		default:
			fprintf(stderr,
				"usage: %s [-r reader] [-c driver] [-d]\n",
				app_name);
			exit(1);
		}
	}
	*argc = optind;

	printf("Using libopensc version %s.\n", sc_get_version());

	memset(&ctx_param, 0, sizeof(ctx_param));
	ctx_param.ver      = 0;
	ctx_param.app_name = app_name;

	i = sc_context_create(&ctx, &ctx_param);
	if (i != SC_SUCCESS) {
		printf("Failed to establish context: %s\n", sc_strerror(i));
		return i;
	}
	ctx->debug = opt_debug;

	if (opt_reader >= sc_ctx_get_reader_count(ctx)) {
		fprintf(stderr, "Illegal reader number.\n"
				"Only %d reader(s) configured.\n",
				sc_ctx_get_reader_count(ctx));
		exit(1);
	}

	while (1) {
		if (opt_reader >= 0) {
			rc = sc_detect_card_presence(sc_ctx_get_reader(ctx, opt_reader));
			printf("Card %s.\n", rc == 1 ? "present" : "absent");
			if (rc < 0)
				return rc;
		} else {
			for (i = rc = 0; rc != 1 && i < sc_ctx_get_reader_count(ctx); i++)
				rc = sc_detect_card_presence(sc_ctx_get_reader(ctx, opt_reader));
			if (rc == 1)
				opt_reader = i - 1;
		}

		if (rc > 0) {
			printf("Card detected in reader '%s'\n",sc_ctx_get_reader(ctx, opt_reader)->name);
			break;
		}
		if (rc < 0)
			return rc;

		printf("Please insert a smart card. Press return to continue");
		fflush(stdout);
		while (getc(stdin) != '\n')
			;
	}

	printf("Connecting... ");
	fflush(stdout);
	i = sc_connect_card(sc_ctx_get_reader(ctx, opt_reader), &card);
	if (i != SC_SUCCESS) {
		printf("Connecting to card failed: %s\n", sc_strerror(i));
		return i;
	}
	printf("connected.\n");
	{
		char tmp[SC_MAX_ATR_SIZE*3];
		sc_bin_to_hex(card->atr, card->atr_len, tmp, sizeof(tmp) - 1, ':');
		printf("ATR = %s\n",tmp);
	}

	if (opt_driver != NULL) {
		rc = sc_set_card_driver(ctx, opt_driver);
		if (rc != 0) {
			fprintf(stderr,
				"Driver '%s' not found!\n", opt_driver);
			return rc;
		}
	}

	return 0;
}
Esempio n. 9
0
int util_connect_card(sc_context_t *ctx, sc_card_t **cardp,
		 int reader_id, int slot_id, int wait, int verbose)
{
	sc_reader_t *reader;
	sc_card_t *card;
	int r;

	if (wait) {
		sc_reader_t *readers[16];
		int slots[16];
		unsigned int i;
		int j, k, found;
		unsigned int event;

		for (i = k = 0; i < sc_ctx_get_reader_count(ctx); i++) {
			if (reader_id >= 0 && (unsigned int)reader_id != i)
				continue;
			reader = sc_ctx_get_reader(ctx, i);
			for (j = 0; j < reader->slot_count; j++, k++) {
				readers[k] = reader;
				slots[k] = j;
			}
		}

		//printf("Waiting for card to be inserted...\n");
		r = sc_wait_for_event(readers, slots, k,
				SC_EVENT_CARD_INSERTED,
				&found, &event, -1);
		if (r < 0) {
			syslog(LOG_ERR,
				"Error while waiting for card: %s\n",
				sc_strerror(r));
			return 3;
		}

		reader = readers[found];
		slot_id = slots[found];
	} else {
		if (sc_ctx_get_reader_count(ctx) == 0) {
			syslog(LOG_ERR,
				"No smart card readers found.\n");
			return 1;
		}
		if (reader_id < 0) {
			unsigned int i;
			/* Automatically try to skip to a reader with a card if reader not specified */
			for (i = 0; i < sc_ctx_get_reader_count(ctx); i++) {
				reader = sc_ctx_get_reader(ctx, i);
				if (sc_detect_card_presence(reader, 0) & SC_SLOT_CARD_PRESENT) {
					reader_id = i;
					syslog(LOG_NOTICE, "Using reader with a card: %s\n", reader->name);
					goto autofound;
				}
			}
			reader_id = 0;
		}
autofound:
		if ((unsigned int)reader_id >= sc_ctx_get_reader_count(ctx)) {
			syslog(LOG_ERR,
				"Illegal reader number. "
				"Only %d reader(s) configured.\n",
				sc_ctx_get_reader_count(ctx));
			return 1;
		}

		reader = sc_ctx_get_reader(ctx, reader_id);
		slot_id = 0;
		if (sc_detect_card_presence(reader, 0) <= 0) {
			syslog(LOG_ERR, "Card not present.\n");
			return 3;
		}
	}

	if (verbose)
		printf("Connecting to card in reader %s...\n", reader->name);
	if ((r = sc_connect_card(reader, slot_id, &card)) < 0) {
		syslog(LOG_ERR,
			"Failed to connect to card: %s\n",
			sc_strerror(r));
		return 1;
	}

	if (verbose)
		printf("Using card driver %s.\n", card->driver->name);

	if ((r = sc_lock(card)) < 0) {
		syslog(LOG_ERR,
			"Failed to lock card: %s\n",
			sc_strerror(r));
		sc_disconnect_card(card, 0);
		return 1;
	}

	*cardp = card;
	return 0;
}
static int pcsc_detect_readers(sc_context_t *ctx, void *prv_data)
{
	struct pcsc_global_private_data *gpriv = (struct pcsc_global_private_data *) prv_data;
	LONG rv;
	DWORD reader_buf_size;
	char *reader_buf = NULL, *reader_name;
	const char *mszGroups = NULL;
	int ret = SC_ERROR_INTERNAL;

	SC_FUNC_CALLED(ctx, 3);

	if (!gpriv) {
		ret = SC_ERROR_NO_READERS_FOUND;
		goto out;
	}

	sc_debug(ctx, "Probing pcsc readers");

	do {
		if (gpriv->pcsc_ctx == -1) {
			/*
			 * Cannot call SCardListReaders with -1
			 * context as in Windows ERROR_INVALID_HANDLE
			 * is returned instead of SCARD_E_INVALID_HANDLE
			 */
			rv = SCARD_E_INVALID_HANDLE;
		}
		else {
			rv = gpriv->SCardListReaders(gpriv->pcsc_ctx, NULL, NULL,
					      (LPDWORD) &reader_buf_size);
		}
		if (rv != SCARD_S_SUCCESS) {
			if (rv != SCARD_E_INVALID_HANDLE) {
				PCSC_ERROR(ctx, "SCardListReaders failed", rv);
				ret = pcsc_ret_to_error(rv);
				goto out;
			}

			sc_debug(ctx, "Establish pcsc context");

			rv = gpriv->SCardEstablishContext(SCARD_SCOPE_USER,
					      NULL, NULL, &gpriv->pcsc_ctx);
			if (rv != SCARD_S_SUCCESS) {
				PCSC_ERROR(ctx, "SCardEstablishContext failed", rv);
				ret = pcsc_ret_to_error(rv);
				goto out;
			}

			rv = SCARD_E_INVALID_HANDLE;
		}
	} while (rv != SCARD_S_SUCCESS);

	reader_buf = (char *) malloc(sizeof(char) * reader_buf_size);
	if (!reader_buf) {
		ret = SC_ERROR_OUT_OF_MEMORY;
		goto out;
	}
	rv = gpriv->SCardListReaders(gpriv->pcsc_ctx, mszGroups, reader_buf,
	                      (LPDWORD) &reader_buf_size);
	if (rv != SCARD_S_SUCCESS) {
		PCSC_ERROR(ctx, "SCardListReaders failed", rv);
		ret = pcsc_ret_to_error(rv);
		goto out;
	}
	for (reader_name = reader_buf; *reader_name != '\x0'; reader_name += strlen (reader_name) + 1) {
		sc_reader_t *reader = NULL;
		struct pcsc_private_data *priv = NULL;
		struct pcsc_slot_data *pslot = NULL;
		sc_slot_info_t *slot = NULL;
		unsigned int i;
		int found = 0;

		for (i=0;i < sc_ctx_get_reader_count (ctx) && !found;i++) {
			sc_reader_t *reader2 = sc_ctx_get_reader (ctx, i);
			if (reader2 == NULL) {
				ret = SC_ERROR_INTERNAL;
				goto err1;
			}
			if (reader2->ops == &pcsc_ops && !strcmp (reader2->name, reader_name)) {
				found = 1;
			}
		}

		/* Reader already available, skip */
		if (found) {
			continue;
		}

		sc_debug(ctx, "Found new pcsc reader '%s'", reader_name);

		if ((reader = (sc_reader_t *) calloc(1, sizeof(sc_reader_t))) == NULL) {
			ret = SC_ERROR_OUT_OF_MEMORY;
			goto err1;
		}
		if ((priv = (struct pcsc_private_data *) malloc(sizeof(struct pcsc_private_data))) == NULL) {
			ret = SC_ERROR_OUT_OF_MEMORY;
			goto err1;
		}
		if ((pslot = (struct pcsc_slot_data *) malloc(sizeof(struct pcsc_slot_data))) == NULL) {
			ret = SC_ERROR_OUT_OF_MEMORY;
			goto err1;
		}

		reader->drv_data = priv;
		reader->ops = &pcsc_ops;
		reader->driver = &pcsc_drv;
		reader->slot_count = 1;
		if ((reader->name = strdup(reader_name)) == NULL) {
			ret = SC_ERROR_OUT_OF_MEMORY;
			goto err1;
		}
		priv->gpriv = gpriv;
		if ((priv->reader_name = strdup(reader_name)) == NULL) {
			ret = SC_ERROR_OUT_OF_MEMORY;
			goto err1;
		}
		slot = &reader->slot[0];
		memset(slot, 0, sizeof(*slot));
		slot->drv_data = pslot;
		memset(pslot, 0, sizeof(*pslot));
		if (_sc_add_reader(ctx, reader)) {
			ret = SC_SUCCESS;	/* silent ignore */
			goto err1;
		}
		refresh_slot_attributes(reader, slot);

		continue;
	
	err1:
		if (priv != NULL) {
			if (priv->reader_name)
				free(priv->reader_name);
			free(priv);
		}
		if (reader != NULL) {
			if (reader->name)
				free(reader->name);
			free(reader);
		}
		if (slot != NULL)
			free(pslot);

		goto out;
	}

	ret = SC_SUCCESS;

out:

	if (reader_buf != NULL)
		free (reader_buf);

	SC_FUNC_RETURN(ctx, 3, ret);
}
Esempio n. 11
0
CK_RV C_Initialize(CK_VOID_PTR pInitArgs)
{
	CK_RV rv;
#if !defined(_WIN32)
	pid_t current_pid = getpid();
#endif
	int rc;
	unsigned int i;
	sc_context_param_t ctx_opts;

	/* Handle fork() exception */
#if !defined(_WIN32)
	if (current_pid != initialized_pid) {
		C_Finalize(NULL_PTR);
	}
	initialized_pid = current_pid;
	in_finalize = 0;
#endif

	if (context != NULL) {
		sc_debug(context, SC_LOG_DEBUG_NORMAL, "C_Initialize(): Cryptoki already initialized\n");
		return CKR_CRYPTOKI_ALREADY_INITIALIZED;
	}

	rv = sc_pkcs11_init_lock((CK_C_INITIALIZE_ARGS_PTR) pInitArgs);
	if (rv != CKR_OK)
		goto out;

	/* set context options */
	memset(&ctx_opts, 0, sizeof(sc_context_param_t));
	ctx_opts.ver        = 0;
	ctx_opts.app_name   = "opensc-pkcs11";
	ctx_opts.thread_ctx = &sc_thread_ctx;
	
	rc = sc_context_create(&context, &ctx_opts);
	if (rc != SC_SUCCESS) {
		rv = CKR_GENERAL_ERROR;
		goto out;
	}

	/* Load configuration */
	load_pkcs11_parameters(&sc_pkcs11_conf, context);

	/* List of sessions */
	list_init(&sessions);
	list_attributes_seeker(&sessions, session_list_seeker);
	
	/* List of slots */
	list_init(&virtual_slots);
	list_attributes_seeker(&virtual_slots, slot_list_seeker);
	
	/* Create a slot for a future "PnP" stuff. */
	if (sc_pkcs11_conf.plug_and_play) {
		create_slot(NULL);
	}
	/* Create slots for readers found on initialization */
	for (i=0; i<sc_ctx_get_reader_count(context); i++) {
		initialize_reader(sc_ctx_get_reader(context, i));
	}

	/* Set initial event state on slots */
	for (i=0; i<list_size(&virtual_slots); i++) {
		sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i);
		slot->events = 0; /* Initially there are no events */
	}

out:	
	if (context != NULL)
		sc_debug(context, SC_LOG_DEBUG_NORMAL, "C_Initialize() = %s", lookup_enum ( RV_T, rv ));

	if (rv != CKR_OK) {
		if (context != NULL) {
			sc_release_context(context);
			context = NULL;
		}
		/* Release and destroy the mutex */
		sc_pkcs11_free_lock();
	}

	return rv;
}
int main(
	int   argc,
	char *argv[]
){
	const struct option options[]={
		{ "help",     0, NULL, 'h' },
		{ "verbose",  0, NULL, 'v' },
		{ "reader",   1, NULL, 'r' },
		{ "pin",      1, NULL, 'p' },
		{ "puk",      1, NULL, 'u' },
		{ "pin0",     1, NULL, '0' },
		{ "pin1",     1, NULL, '1' },
		{ NULL, 0, NULL, 0 }
	};
	sc_context_t *ctx;
	sc_context_param_t ctx_param;
	sc_card_t *card;
	int do_help=0, do_unblock=0, do_change=0, do_nullpin=0, do_readcert=0, do_writecert=0;
	u8 newpin[32];
	char *certfile=NULL, *p;
	int r, oerr=0, reader=0, debug=0, newlen=0, pin_nr=-1, cert_nr=-1;
	size_t i;

	while((r=getopt_long(argc,argv,"hvr:p:u:0:1:",options,NULL))!=EOF) switch(r){
		case 'h': ++do_help; break;
		case 'v': ++debug; break;
		case 'r': reader=atoi(optarg); break;
		case 'p': set_pin(pinlist[0].value, &pinlist[0].len, optarg); break;
		case 'u': set_pin(pinlist[1].value, &pinlist[1].len, optarg); break;
		case '0': set_pin(pinlist[2].value, &pinlist[2].len, optarg); break;
		case '1': set_pin(pinlist[3].value, &pinlist[3].len, optarg); break;
		default: ++oerr;
	}
	if(do_help){
		fprintf(stderr,"This is netkey-tool V1.0, May 15 2005, Copyright Peter Koch <*****@*****.**>\n");
		fprintf(stderr,"usage: %s <options> command\n", argv[0]);
		fprintf(stderr,"\nOptions:\n");
		fprintf(stderr,"  -v                       : verbose, may be specified several times\n");
		fprintf(stderr,"  --reader <num>, -r <num> : use reader num (default 0)\n");
		fprintf(stderr,"  --pin <pin>, -p <pin>    : current value of global PIN\n");
		fprintf(stderr,"  --puk <pin>, -u <pin>    : current value of global PUK\n");
		fprintf(stderr,"  --pin0 <pin>, -0 <pin>   : current value of local PIN0\n");
		fprintf(stderr,"  --pin1 <pin>, -1 <pin>   : current value of local PIN1\n");
		fprintf(stderr,"\nCommands:\n");
		fprintf(stderr,"  unblock {pin | pin0 | pin1}\n");
		fprintf(stderr,"  change {pin | puk | pin0 | pin1} <new pin>\n");
		fprintf(stderr,"  nullpin <new pin>\n");
		fprintf(stderr,"  cert <certnum> <filepath>\n");
		fprintf(stderr,"  cert <filepath> <certnum>\n");
		fprintf(stderr,"\nExamples:\n");
		fprintf(stderr,"list PINs and Certs without changing anything. Try this first!!\n");
		fprintf(stderr,"  %s\n", argv[0]);
		fprintf(stderr,"\nlist PINs and Certs and initial PUK-value (after verification of global PIN)\n");
		fprintf(stderr,"  %s --pin 123456\n", argv[0]);
		fprintf(stderr,"\nchange local PIN0 to 654321 after verification of global PIN\n");
		fprintf(stderr,"  %s --pin 123456 change pin0 654321\n", argv[0]);
		fprintf(stderr,"\nchange global PIN from hex 01:02:03:04:05:06 to ascii 123456\n");
		fprintf(stderr,"  %s --pin 01:02:03:04:05:06 change pin 123456\n", argv[0]);
		fprintf(stderr,"\nunblock global PIN with global PUK\n");
		fprintf(stderr,"  %s --puk 12345678 unblock pin\n", argv[0]);
		fprintf(stderr,"\nset global PIN to initial value when in NullPin-state\n");
		fprintf(stderr,"  %s nullpin 123456\n", argv[0]);
		fprintf(stderr,"\nstore Certificate into card at position 2 and read it back into file\n");
		fprintf(stderr,"  %s --pin1 123456 cert /tmp/cert1 2\n", argv[0]);
		fprintf(stderr,"  %s cert 2 /tmp/cert2\n", argv[0]);
		fprintf(stderr,"\nBe carful - this tool may destroy your card\n");
		fprintf(stderr,"\nQuestions? Comments? ==> [email protected]\n");
		exit(1);
	}
	if(optind==argc-2 && !strcmp(argv[optind],"unblock")){
		++optind, do_unblock=1;
		pin_nr=pin_string2int(argv[optind++]);
		if(pin_nr<0 || pin_nr==1) ++oerr;
	}
	if(optind==argc-3 && !strcmp(argv[optind],"change")){
		++optind, do_change=1;
		pin_nr=pin_string2int(argv[optind++]);
		if(pin_nr<0 || pin_nr>3) ++oerr;
		set_pin(newpin,&newlen,argv[optind++]);
	}
	if(optind==argc-2 && !strcmp(argv[optind],"nullpin")){
		++optind, do_nullpin=1;
		set_pin(newpin,&newlen,argv[optind++]);
	}
	if(optind==argc-3 && !strcmp(argv[optind],"cert")){
		++optind;
		cert_nr=strtol(argv[optind],&p,10);
		if(argv[optind][0] && !*p && cert_nr>=0 && cert_nr<(int)(sizeof(certlist)/sizeof(certlist[0]))){
			do_readcert=1, certfile=argv[optind+1];
		} else {
			do_writecert=1, certfile=argv[optind];
			cert_nr=strtol(argv[optind+1],&p,10);
			if(!argv[optind][0] || *p || cert_nr<0 || cert_nr>=(int)(sizeof(certlist)/sizeof(certlist[0]))) ++oerr;
		}
		optind+=2;
	}
	if(oerr || optind!=argc){
		fprintf(stderr,"%s: invalid usage, try --help\n", argv[0]);
		exit(1);
	}

	memset(&ctx_param, 0, sizeof(ctx_param));
	ctx_param.ver      = 0;
	ctx_param.app_name = argv[0];

	r = sc_context_create(&ctx, &ctx_param);
	if(r < 0){
		fprintf(stderr,"Establish-Context failed: %s\n", sc_strerror(r));
		exit(1);
	}
	ctx->debug=debug;
	if(ctx->debug>0)
		printf("Context for application \"%s\" created, Debug=%d\n", ctx->app_name, ctx->debug);

	for(i=0;ctx->card_drivers[i];++i)
		if(!strcmp("tcos", ctx->card_drivers[i]->short_name)) break;
	if(!ctx->card_drivers[i]){
		fprintf(stderr,"Context does not support TCOS-cards\n");
		exit(1);
	}

	printf("%d Reader detected\n", sc_ctx_get_reader_count(ctx));
	for(i=0; i < sc_ctx_get_reader_count(ctx); ++i){
		sc_reader_t *myreader = sc_ctx_get_reader(ctx, i);
		printf("%lu: %s, Driver: %s, %d Slot(s)\n",
			(unsigned long) i, myreader->name,
			myreader->driver->name, myreader->slot_count);
	}
	if(reader < 0 || reader >= (int)sc_ctx_get_reader_count(ctx)){
		fprintf(stderr,"Cannot open reader %d\n", reader);
		exit(1);
	}

	if((r = sc_connect_card(sc_ctx_get_reader(ctx, 0), 0, &card))<0){
		fprintf(stderr,"Connect-Card failed: %s\n", sc_strerror(r));
		exit(1);
	}
	printf("\nCard detected (driver: %s)\nATR:", card->driver->name);
	for(i=0;i<card->atr_len;++i) printf("%c%02X", i?':':' ', card->atr[i]); printf("\n");

	if((r = sc_lock(card))<0){
		fprintf(stderr,"Lock failed: %s\n", sc_strerror(r));
		exit(1);
	}

	show_card(card);

	if(do_unblock || do_change){
		int i1=pinlist[pin_nr].p1, i2=pinlist[pin_nr].p2; 

		if((do_unblock || !pinlist[pin_nr].len) &&
		   (i1<0 || !pinlist[i1].len) && (i2<0 || !pinlist[i2].len)
		){
			fprintf(stderr, "\nNeed %s", do_change ? pinlist[pin_nr].label : pinlist[i1].label);
			if(do_change && i1>=0) fprintf(stderr, " or %s", pinlist[i1].label);
			if(i2>=0) fprintf(stderr, " or %s", pinlist[i2].label);
			fprintf(stderr, " to %s %s\n", do_change ? "change" : "unblock", pinlist[pin_nr].label);
		} else {
			if(do_change && pinlist[pin_nr].len) i1=pin_nr;
			if(i1<0 || !pinlist[i1].len) i1=i2;
			handle_change(card, pin_nr, i1, do_change, newpin, newlen);
		}
	}

	if(do_nullpin){
		handle_nullpin(card, newpin, newlen);
		show_initial_puk(card);
	}

	if(do_readcert) handle_readcert(card, cert_nr, certfile);
	if(do_writecert){
		if(certlist[cert_nr].readonly){
			fprintf(stderr, "\nReadonly-Certificate %d cannot be changed\n", cert_nr);
		} else if(!pinlist[0].len && !pinlist[3].len){
			fprintf(stderr, "\nNeed %s or %s to change Card-Certificate %d\n",
				pinlist[0].label, pinlist[3].label, cert_nr
			);
		} else handle_writecert(card, cert_nr, certfile);
	}

	if(do_unblock+do_change+do_nullpin+do_readcert==0) show_certs(card);

	sc_unlock(card);
	sc_disconnect_card(card,0);
	sc_release_context(ctx);

	exit(0);
}