Пример #1
0
int ykp_configure_for(YKP_CONFIG *cfg, int confnum, YK_STATUS *st)
{
	ykp_configure_version(cfg, st);
	switch(confnum) {
	case 1:
		memcpy(&cfg->ykcore_config, &default_config1,
				sizeof(default_config1));
		return ykp_configure_command(cfg, SLOT_CONFIG);
	case 2:
		memcpy(&cfg->ykcore_config, &default_config2,
				sizeof(default_config2));
		return ykp_configure_command(cfg, SLOT_CONFIG2);
	default:
		ykp_errno = YKP_EINVCONFNUM;
		return 0;
	}
}
void YubiKeyWriter::exportConfig(YubiKeyConfig *ykConfig) {
    YubiKeyFinder::getInstance()->stop();

    YK_KEY *yk = 0;
    YK_STATUS *ykst = YubiKeyFinder::getInstance()->status();
    YKP_CONFIG *cfg = ykp_alloc();

    bool error = false;

    qDebug() << "-------------------------";
    qDebug() << "Starting write config";
    qDebug() << "-------------------------";

    try {
        if (!(yk = yk_open_first_key())) {
            throw 0;
        }

        ykp_configure_version(cfg, ykst);

        qDebug() << "writer:configuration slot:" << ykConfig->configSlot();

        bool useAccessCode;
        unsigned char accessCode[MAX_SIZE];

        if(!assembleConfig(ykConfig, cfg, &useAccessCode, accessCode)) {
            throw 0;
        }

        m_filename = QFileDialog::getSaveFileName(NULL, tr("Export File"), m_filename, tr("Yubico cfg format (*.ycfg)"), NULL);

        char data[1024];
        int len = ykp_export_config(cfg, data, 1024, YKP_FORMAT_YCFG);
        if(!len) {
            throw 0;
        }

        QFile file(m_filename);
        if(!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
            throw 0;
        }
        if(!file.write(data, len)) {
            throw 0;
        }
        file.close();

        QSettings settings;
        settings.setValue(SG_EXPORT_FILENAME, m_filename);

        emit configWritten(true, NULL);
        emit diagnostics(QString("Exported config to file %1").arg(m_filename));
    }
    catch(...) {
        error = true;
    }

    if (cfg) {
        ykp_free_config(cfg);
    }

    if (yk && !yk_close_key(yk)) {
        error = true;
    }

    YubiKeyFinder::getInstance()->start();

    if(error) {
        qDebug() << "Config not exported";
        QString errMsg = reportError();
        emit configWritten(false, errMsg);
    }
}
void YubiKeyWriter::writeConfig(YubiKeyConfig *ykConfig) {

    YubiKeyFinder::getInstance()->stop();

    YK_KEY *yk = 0;
    YK_STATUS *ykst = YubiKeyFinder::getInstance()->status();
    YKP_CONFIG *cfg = ykp_alloc();

    bool error = false;

    qDebug() << "-------------------------";
    qDebug() << "Starting write config";
    qDebug() << "-------------------------";

    try {
        if (!(yk = yk_open_first_key())) {
            throw 0;
        } else if (!yk_get_status(yk, ykst)) {
            throw 0;
        }

        ykp_configure_version(cfg, ykst);

        qDebug() << "writer:configuration slot:" << ykConfig->configSlot();

        bool useAccessCode;
        unsigned char accessCode[MAX_SIZE];

        if(!assembleConfig(ykConfig, cfg, &useAccessCode, accessCode)) {
            throw 0;
        }

        //Log configuration...
        qDebug() << "-------------------------";
        qDebug() << "Config data to be written to key configuration...";

        char conf_buf[1024];
        ykp_export_config(cfg, conf_buf, 1024, YKP_FORMAT_LEGACY);
        qDebug() << conf_buf;

        qDebug() << "-------------------------";

        // Write configuration...
        if (!yk_write_command(yk,
                              ykp_core_config(cfg), ykp_command(cfg),
                              useAccessCode ? accessCode : NULL)) {
            qDebug() << "Failure";
            throw 0;
        }
        qDebug() << "Success... config written";
        emit diagnostics(QString("Successfully wrote config to slot %1").arg(ykp_config_num(cfg)));

        YubiKeyLogger::logConfig(ykConfig);
        emit configWritten(true, NULL);
    }
    catch(...) {
        error = true;
    }

    if (cfg) {
        ykp_free_config(cfg);
    }

    if (yk && !yk_close_key(yk)) {
        error = true;
    }

    YubiKeyFinder::getInstance()->start();

    if(error) {
        qDebug() << "Config not written";
        QString errMsg = reportError();
        emit configWritten(false, errMsg);
    }

    qDebug() << "-------------------------";
    qDebug() << "Stopping write config";
    qDebug() << "-------------------------";
}
int _test_non_config_args(void)
{
	YKP_CONFIG *cfg = ykp_alloc();
	YK_STATUS *st = _test_init_st(2, 2, 0);
	int rc = 0;

	const char *infname = NULL;
	const char *outfname = NULL;
	bool verbose = false;
	bool aesviahash = false;
	bool use_access_code = false;
	unsigned char access_code[256];
	YK_KEY *yk = 0;
	bool autocommit = false;
	int exit_code = 0;
	int i;

	/* Options */
	char *salt = NULL;
	char ndef[128];
	char ndef_type = NULL;
	unsigned char usb_mode = -1;
	bool zap = false;

	unsigned char scan_map[sizeof(SCAN_MAP)];

	char *argv[] = {
		"unittest", "-1", "-sout", "-iin", "-c313233343536", "-y", "-v",
		NULL
	};
	int argc = 7;

	ykp_errno = 0;

/* getopt reinit (BSD systems use optreset and a different optind value) */
#if defined(__GLIBC__) || defined(_WIN32)
	optind = 0;
#else
	optind = optreset = 1;
#endif

	/* copy version number from st into cfg */
  ykp_configure_version(cfg, st);
	//assert(ykp_configure_for(cfg, 1, st) == 1);

	/* call args_to_config from ykpers-args.c with a fake set of program arguments */
	rc = args_to_config(argc, argv, cfg, yk,
			    &infname, &outfname,
			    &autocommit, salt,
			    st, &verbose,
			    access_code, &use_access_code,
			    &aesviahash, &ndef_type, ndef, &usb_mode, &zap,
			    scan_map, &exit_code);
	assert(rc == 1);
	i = strcmp(infname, "in"); assert(i == 0);
	i = strcmp(outfname, "out"); assert(i == 0);
	i = strcmp(access_code, "123456"); assert(i == 0);
	assert(autocommit == true);
	assert(verbose == true);

	ykp_free_config(cfg);
	free(st);
}
Пример #5
0
/*
 * Parse all arguments supplied to this program and turn it into mainly
 * a YKP_CONFIG (but return some other parameters as well, like
 * access_code, verbose etc.).
 *
 * Done in this way to be testable (see tests/test_args_to_config.c).
 */
int args_to_config(int argc, char **argv, YKP_CONFIG *cfg, YK_KEY *yk,
		   const char **infname, const char **outfname,
		   bool *autocommit, char *salt,
		   YK_STATUS *st, bool *verbose,
		   unsigned char *access_code, bool *use_access_code,
		   bool *aesviahash, char *ndef_type, char *ndef,
		   unsigned char *usb_mode, bool *zap,
		   unsigned char *scan_bin, int *exit_code)
{
	int c;
	const char *aeshash = NULL;
	bool new_access_code = false;
	bool slot_chosen = false;
	bool mode_chosen = false;
	bool option_seen = false;
	bool swap_seen = false;
	bool update_seen = false;
	bool ndef_seen = false;
	bool usb_mode_seen = false;
	bool scan_map_seen = false;
	struct config_st *ycfg;

	ykp_configure_version(cfg, st);

	ycfg = (struct config_st *) ykp_core_config(cfg);

	while((c = getopt(argc, argv, optstring)) != -1) {
		if (c == 'o') {
			if (strcmp(optarg, "oath-hotp") == 0 ||
			    strcmp(optarg, "chal-resp") == 0) {
				if (mode_chosen) {
					fprintf(stderr, "You may only choose mode (-ooath-hotp / "
						"-ochal-resp) once.\n");
					*exit_code = 1;
					return 0;
				}

				if (option_seen) {
					fprintf(stderr, "Mode choosing flags (oath-hotp / chal-resp) "
						"must be set prior to any other options (-o).\n");
					*exit_code = 1;
					return 0;
				}

				/* The default flags (particularly for slot 2) does not apply to
				 * these new modes of operation found in Yubikey >= 2.1. Therefor,
				 * we reset them here and, as a consequence of that, require the
				 * mode choosing options to be specified before any other.
				 */
				ycfg->tktFlags = 0;
				ycfg->cfgFlags = 0;
				ycfg->extFlags = 0;

				mode_chosen = 1;
			}

			option_seen = true;
		}

		switch (c) {
		case 'u':
			if (slot_chosen) {
				fprintf(stderr, "You must use update before slot (-1 / -2).\n");
				*exit_code = 1;
				return 0;
			}
			if (swap_seen) {
				fprintf(stderr, "Update (-u) and swap (-x) can't be combined.\n");
				*exit_code = 1;
				return 0;
			}
			if (ndef_seen) {
				fprintf(stderr, "Update (-u) can not be combined with ndef (-n).\n");
				*exit_code = 1;
				return 0;
			}
			update_seen = true;
			break;
		case '1':
		case '2': {
				int command;
				if (slot_chosen) {
					fprintf(stderr, "You may only choose slot (-1 / -2) once.\n");
					*exit_code = 1;
					return 0;
				}
				if (option_seen) {
					fprintf(stderr, "You must choose slot before any options (-o).\n");
					*exit_code = 1;
					return 0;
				}
				if (swap_seen) {
					fprintf(stderr, "You can not combine slot swap (-x) with configuring a slot.\n");
					*exit_code = 1;
					return 0;
				}
				ykp_set_tktflag_APPEND_CR(cfg, true);
				if (update_seen) {
					ykp_set_extflag_ALLOW_UPDATE(cfg, true);
					if(c == '1') {
						command = SLOT_UPDATE1;
					} else if(c == '2') {
						command = SLOT_UPDATE2;
					}
				} else if (c == '1') {
					command = SLOT_CONFIG;
				} else if (c == '2') {
					command = SLOT_CONFIG2;
					ykp_set_cfgflag_STATIC_TICKET(cfg, true);
					ykp_set_cfgflag_STRONG_PW1(cfg, true);
					ykp_set_cfgflag_STRONG_PW2(cfg, true);
					ykp_set_cfgflag_MAN_UPDATE(cfg, true);

				}
				if (!ykp_configure_command(cfg, command))
					return 0;
				slot_chosen = true;
				break;
			}
		case 'x':
			if (slot_chosen || option_seen || update_seen || ndef_seen || *zap || usb_mode_seen || scan_map_seen) {
				fprintf(stderr, "Slot swap (-x) can not be used with other options.\n");
				*exit_code = 1;
				return 0;
			}

			if (!ykp_configure_command(cfg, SLOT_SWAP)) {
				return 0;
			}
			swap_seen = true;
			break;
		case 'z':
			if (swap_seen || update_seen || ndef_seen || usb_mode_seen || scan_map_seen) {
				fprintf(stderr, "Zap (-z) can only be used with a slot (-1 / -2).\n");
				*exit_code = 1;
				return 0;
			}
			*zap = true;
			break;
		case 'i':
			*infname = optarg;
			break;
		case 's':
			*outfname = optarg;
			break;
		case 'a':
			*aesviahash = true;
			aeshash = optarg;
			break;
		case 'c': {
			size_t access_code_len = 0;
			int rc = hex_modhex_decode(access_code, &access_code_len,
						   optarg, strlen(optarg),
						   12, 12, false);
			if (rc <= 0) {
				fprintf(stderr,
					"Invalid access code string: %s\n",
					optarg);
				*exit_code = 1;
				return 0;
			}
			if (!new_access_code)
				ykp_set_access_code(cfg,
						    access_code,
						    access_code_len);
			*use_access_code = true;
			break;
		}
		case 't':
			*ndef_type = 'T';
		case 'n': {
				  int command;
				  if(!*ndef_type) {
					  *ndef_type = 'U';
				  }
				  if (swap_seen || update_seen || option_seen || *zap || usb_mode_seen || scan_map_seen) {
					  fprintf(stderr, "Ndef (-n/-t) can only be used with a slot (-1/-2).\n");
					  *exit_code = 1;
					  return 0;
				  }
				  if(ykp_command(cfg) == SLOT_CONFIG) {
					  command = SLOT_NDEF;
				  } else if(ykp_command(cfg) == SLOT_CONFIG2) {
					  command = SLOT_NDEF2;
				  } else {
					  command = SLOT_NDEF;
				  }
				  if (!ykp_configure_command(cfg, command)) {
					  return 0;
				  }
				  memcpy(ndef, optarg, strlen(optarg));
				  ndef_seen = true;
				  break;
			  }
		case 'm':
			if(slot_chosen || swap_seen || update_seen || option_seen || ndef_seen || *zap || scan_map_seen) {
				fprintf(stderr, "USB mode (-m) can not be combined with other options.\n");
				*exit_code = 1;
				return 0;
			}
			if(optarg[1] != '\0') {
				*usb_mode = (optarg[0] - '0') << 4;
				optarg++;
			}
			if(optarg[1] == '\0') {
				int mode = optarg[0] - '0';
				if(mode >= 0 && mode < MODE_MASK) {
					*usb_mode |= mode;
					usb_mode_seen = true;
				}
			}
			/* Only true if we've parsed a valid USB mode number */
			if(!usb_mode_seen) {
				fprintf(stderr, "Invalid USB operation mode.\n");
				*exit_code = 1;
				return 0;
			}
			if (!ykp_configure_command(cfg, SLOT_DEVICE_CONFIG))
				return 0;

			break;
		case 'S':
			{
				size_t scanlength = strlen(SCAN_MAP);
				if(slot_chosen || swap_seen || update_seen || option_seen || ndef_seen || *zap || usb_mode_seen) {
					fprintf(stderr, "Scanmap (-S) can not be combined with other options.\n");
					*exit_code = 1;
					return 0;
				}
				if(optarg) {
					size_t scanbinlen;
					size_t scanlen = strlen (optarg);
					int rc = hex_modhex_decode(scan_bin, &scanbinlen,
							optarg, scanlen,
							scanlength * 2, scanlength * 2,
							false);

					if (rc <= 0) {
						fprintf(stderr,
								"Invalid scanmap string %s\n",
								optarg);
						*exit_code = 1;
						return 0;
					}
				} else {
					memset(scan_bin, 0, scanlength);
				}
				scan_map_seen = true;
			}
			if (!ykp_configure_command(cfg, SLOT_SCAN_MAP))
				return 0;
			break;
		case 'o':
			if (*zap) {
				fprintf(stderr, "No options can be given with zap (-z).\n");
				*exit_code = 1;
				return 0;
			}
			if (strncmp(optarg, "salt=", 5) == 0)
				salt = strdup(optarg+5);
			else if (strncmp(optarg, "fixed=", 6) == 0) {
				if (_set_fixed(optarg + 6, cfg) != 1) {
					fprintf(stderr,
						"Invalid fixed string: %s\n",
						optarg + 6);
					*exit_code = 1;
					return 0;
				}
			}
			else if (strncmp(optarg, "uid=", 4) == 0) {
				const char *uid = optarg+4;
				size_t uidlen = strlen (uid);
				unsigned char uidbin[256];
				size_t uidbinlen = 0;
				int rc = hex_modhex_decode(uidbin, &uidbinlen,
							   uid, uidlen,
							   12, 12, false);
				if (rc <= 0) {
					fprintf(stderr,
						"Invalid uid string: %s\n",
						uid);
					*exit_code = 1;
					return 0;
				}
				/* for OATH-HOTP and CHAL-RESP, uid is not applicable */
				if ((ycfg->tktFlags & TKTFLAG_OATH_HOTP) == TKTFLAG_OATH_HOTP ||
				    (ycfg->tktFlags & TKTFLAG_CHAL_RESP) == TKTFLAG_CHAL_RESP) {
					fprintf(stderr,
						"Option uid= not valid with -ooath-hotp or -ochal-resp.\n"
						);
					*exit_code = 1;
					return 0;
				}
				ykp_set_uid(cfg, uidbin, uidbinlen);
			}
			else if (strncmp(optarg, "access=", 7) == 0) {
				const char *acc = optarg+7;
				size_t acclen = strlen (acc);
				unsigned char accbin[256];
				size_t accbinlen = 0;
				int rc = hex_modhex_decode (accbin, &accbinlen,
							    acc, acclen,
							    12, 12, false);
				if (rc <= 0) {
					fprintf(stderr,
						"Invalid access code string: %s\n",
						acc);
					*exit_code = 1;
					return 0;
				}
				ykp_set_access_code(cfg, accbin, accbinlen);
				new_access_code = true;
			}
#define TKTFLAG(o, f)							\
			else if (strcmp(optarg, o) == 0) {		\
				if (!ykp_set_tktflag_##f(cfg, true)) {	\
					*exit_code = 1;			\
					return 0;		\
				}					\
			} else if (strcmp(optarg, "-" o) == 0) {	\
				if (! ykp_set_tktflag_##f(cfg, false)) { \
					*exit_code = 1;			\
					return 0;		\
				}					\
			}
			TKTFLAG("tab-first", TAB_FIRST)
			TKTFLAG("append-tab1", APPEND_TAB1)
			TKTFLAG("append-tab2", APPEND_TAB2)
			TKTFLAG("append-delay1", APPEND_DELAY1)
			TKTFLAG("append-delay2", APPEND_DELAY2)
			TKTFLAG("append-cr", APPEND_CR)
			TKTFLAG("protect-cfg2", PROTECT_CFG2)
			TKTFLAG("oath-hotp", OATH_HOTP)
			TKTFLAG("chal-resp", CHAL_RESP)
#undef TKTFLAG

#define CFGFLAG(o, f)							\
			else if (strcmp(optarg, o) == 0) {		\
				if (! ykp_set_cfgflag_##f(cfg, true)) {	\
					*exit_code = 1;			\
					return 0;			\
				}					\
			} else if (strcmp(optarg, "-" o) == 0) {	\
				if (! ykp_set_cfgflag_##f(cfg, false)) { \
					*exit_code = 1;			\
					return 0;			\
				}					\
			}
			CFGFLAG("send-ref", SEND_REF)
			CFGFLAG("ticket-first", TICKET_FIRST)
			CFGFLAG("pacing-10ms", PACING_10MS)
			CFGFLAG("pacing-20ms", PACING_20MS)
			CFGFLAG("allow-hidtrig", ALLOW_HIDTRIG)
			CFGFLAG("static-ticket", STATIC_TICKET)
			CFGFLAG("short-ticket", SHORT_TICKET)
			CFGFLAG("strong-pw1", STRONG_PW1)
			CFGFLAG("strong-pw2", STRONG_PW2)
			CFGFLAG("man-update", MAN_UPDATE)
			CFGFLAG("oath-hotp8", OATH_HOTP8)
			CFGFLAG("oath-fixed-modhex1", OATH_FIXED_MODHEX1)
			CFGFLAG("oath-fixed-modhex2", OATH_FIXED_MODHEX2)
			CFGFLAG("oath-fixed-modhex", OATH_FIXED_MODHEX)
			CFGFLAG("chal-yubico", CHAL_YUBICO)
			CFGFLAG("chal-hmac", CHAL_HMAC)
			CFGFLAG("hmac-lt64", HMAC_LT64)
			CFGFLAG("chal-btn-trig", CHAL_BTN_TRIG)
#undef CFGFLAG
			else if (strncmp(optarg, "oath-imf=", 9) == 0) {
				unsigned long imf;

				if (!(ycfg->tktFlags & TKTFLAG_OATH_HOTP) == TKTFLAG_OATH_HOTP) {
					fprintf(stderr,
						"Option oath-imf= only valid with -ooath-hotp or -ooath-hotp8.\n"
						);
					*exit_code = 1;
					return 0;
				}

				if (sscanf(optarg+9, "%lu", &imf) != 1 ||
				    /* yubikey limitations */
				    imf > 65535*16 || imf % 16 != 0) {
					fprintf(stderr,
						"Invalid value %s for oath-imf=.\n", optarg+9
						);
					*exit_code = 1;
					return 0;
				}
				if (! ykp_set_oath_imf(cfg, imf)) {
					*exit_code = 1;
					return 0;
				}
			}
			else if (strncmp(optarg, "oath-id=", 8) == 0 || strcmp(optarg, "oath-id") == 0) {
				if (_set_oath_id(optarg, cfg, ycfg, yk, st) != 1) {
					*exit_code = 1;
					return 0;
				}
			}

#define EXTFLAG(o, f)							\
			else if (strcmp(optarg, o) == 0) {		\
				if (! ykp_set_extflag_##f(cfg, true)) {	\
					*exit_code = 1;			\
					return 0;			\
				}					\
			} else if (strcmp(optarg, "-" o) == 0) {	\
				if (! ykp_set_extflag_##f(cfg, false)) { \
					*exit_code = 1;			\
					return 0;			\
				}					\
			}
			EXTFLAG("serial-btn-visible", SERIAL_BTN_VISIBLE)
			EXTFLAG("serial-usb-visible", SERIAL_USB_VISIBLE)
			EXTFLAG("serial-api-visible", SERIAL_API_VISIBLE)
      EXTFLAG("use-numeric-keypad", USE_NUMERIC_KEYPAD)
      EXTFLAG("fast-trig", FAST_TRIG)
			EXTFLAG("allow-update", ALLOW_UPDATE)
      EXTFLAG("dormant", DORMANT)
#undef EXTFLAG
			else {
				fprintf(stderr, "Unknown option '%s'\n",
					optarg);
				fputs(usage, stderr);
				*exit_code = 1;
				return 0;
			}
			break;
		case 'v':
			*verbose = true;
			break;
		case 'y':
			*autocommit = true;
			break;
		case 'h':
		default:
			fputs(usage, stderr);
			*exit_code = 0;
			return 0;
		}
	}

	if (!slot_chosen && !ndef_seen && !swap_seen && !usb_mode_seen && !scan_map_seen) {
		fprintf(stderr, "A slot must be chosen with -1 or -2.\n");
		*exit_code = 1;
		return 0;
	}

	if (update_seen) {
		struct config_st *core_config = (struct config_st *) ykp_core_config(cfg);
		if ((core_config->tktFlags & TKTFLAG_UPDATE_MASK) != core_config->tktFlags) {
			fprintf(stderr, "Unallowed ticket flags with update.\n");
			*exit_code = 1;
			return 0;
		}
		if ((core_config->cfgFlags & CFGFLAG_UPDATE_MASK) != core_config->cfgFlags) {
			fprintf(stderr, "Unallowed cfg flags with update.\n");
			*exit_code = 1;
			return 0;
		}
		if ((core_config->extFlags & EXTFLAG_UPDATE_MASK) != core_config->extFlags) {
			fprintf(stderr, "Unallowed ext flags with update.\n");
			*exit_code = 1;
			return 0;
		}
	}

	if (*aesviahash) {
		bool long_key_valid = false;
		int res = 0;

		/* for OATH-HOTP, 160 bits key is also valid */
		if ((ycfg->tktFlags & TKTFLAG_OATH_HOTP) == TKTFLAG_OATH_HOTP)
			long_key_valid = true;

		/* for HMAC (not Yubico) challenge-response, 160 bits key is also valid */
		if ((ycfg->tktFlags & TKTFLAG_CHAL_RESP) == TKTFLAG_CHAL_RESP &&
		    (ycfg->cfgFlags & CFGFLAG_CHAL_HMAC) == CFGFLAG_CHAL_HMAC) {
			long_key_valid = true;
		}

		if (long_key_valid && strlen(aeshash) == 40) {
			res = ykp_HMAC_key_from_hex(cfg, aeshash);
		} else {
			res = ykp_AES_key_from_hex(cfg, aeshash);
		}

		if (res) {
			fprintf(stderr, "Bad %s key: %s\n", long_key_valid ? "HMAC":"AES", aeshash);
			fflush(stderr);
			return 0;
		}
	}

	return 1;
}
static void _test_non_config_args(void)
{
	YKP_CONFIG *cfg = ykp_alloc();
	YK_STATUS *st = _test_init_st(2, 2, 0);
	int rc = 0;

	const char *infname = NULL;
	const char *outfname = NULL;
	bool verbose = false;
	bool dry_run = false;
	char keylocation = 0;
	bool use_access_code = false;
	unsigned char access_code[256];
	bool autocommit = false;
	int exit_code = 0;
	int i;
	int data_format = YKP_FORMAT_LEGACY;

	/* Options */
	char oathid[128] = {0};
	char ndef[128];
	char ndef_type = 0;
	unsigned char usb_mode = 0;
	unsigned char cr_timeout = 0;
	unsigned short autoeject_timeout = 0;
	int num_modes_seen = 0;
	bool zap = false;

	unsigned char scan_map[sizeof(SCAN_MAP)];

	char *argv[] = {
		"unittest", "-1", "-sout", "-iin", "-c313233343536", "-y", "-v",
		NULL
	};
	int argc = 7;

	ykp_errno = 0;

/* getopt reinit (BSD systems use optreset and a different optind value) */
#if defined(__GLIBC__) || defined(_WIN32)
	optind = 0;
#else
	optind = optreset = 1;
#endif

	/* copy version number from st into cfg */
  ykp_configure_version(cfg, st);
	//assert(ykp_configure_for(cfg, 1, st) == 1);

	/* call args_to_config from ykpers-args.c with a fake set of program arguments */
	rc = args_to_config(argc, argv, cfg, oathid,
			    &infname, &outfname,
			    &data_format, &autocommit,
			    st, &verbose, &dry_run,
			    access_code, &use_access_code,
			    &keylocation, &ndef_type, ndef, &usb_mode, &zap,
			    scan_map, &cr_timeout, &autoeject_timeout, &num_modes_seen,
			    &exit_code);
	assert(rc == 1);
	i = strcmp(infname, "in"); assert(i == 0);
	i = strcmp(outfname, "out"); assert(i == 0);
	i = memcmp(access_code, "123456", 6); assert(i == 0);
	assert(autocommit == true);
	assert(verbose == true);

	ykp_free_config(cfg);
	free(st);
}