int main (int argc, char *argv[]) { int client_id; char *token, *url = NULL, *api_key = NULL; int ret; parse_args (argc, argv, &client_id, &token, &url, &api_key); /* Debug. */ fprintf (stderr, "Input:\n"); if (url) fprintf (stderr, " validation URL: %s\n", url); fprintf (stderr, " client id: %d\n", client_id); fprintf (stderr, " token: %s\n", token); if (api_key != NULL) fprintf (stderr, " api key: %s\n", api_key); ret = ykclient_verify_otp_v2 (NULL, token, client_id, NULL, 1, (const char **) &url, api_key); printf ("Verification output (%d): %s\n", ret, ykclient_strerror (ret)); if (ret != YKCLIENT_OK) return EXIT_FAILURE; return EXIT_SUCCESS; }
void test_v1_validation(int client_id, char *client_b64key) { ykclient_t *ykc; int ret; TEST(("init self")); ret = ykclient_init (&ykc); printf ("ykclient_init (%d): %s\n", ret, ykclient_strerror (ret)); assert(ret == YKCLIENT_OK); ykclient_set_url_template (ykc, "http://api.yubico.com/wsapi/verify?id=%d&otp=%s"); TEST(("null client_id, expect REPLAYED_OTP")); ykclient_set_verify_signature(ykc, 0); ykclient_set_client (ykc, client_id, 0, NULL); #ifndef TEST_WITHOUT_INTERNET ret = ykclient_request (ykc, "dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh"); printf ("ykclient_request (%d): %s\n", ret, ykclient_strerror (ret)); printf ("used url: %s\n", ykclient_get_last_url (ykc)); assert(ret == YKCLIENT_REPLAYED_OTP); #else printf ("Test SKIPPED\n"); #endif /* Test signed request. When signing requests to a v1 service, we must clear the nonce first. */ TEST(("signed request, expect REPLAYED_OTP")); ykclient_set_verify_signature(ykc, 1); ykclient_set_client_b64 (ykc, client_id, client_b64key); ykclient_set_nonce(ykc, NULL); #ifndef TEST_WITHOUT_INTERNET ret = ykclient_request (ykc, "dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh"); printf ("ykclient_request (%d): %s\n", ret, ykclient_strerror (ret)); printf ("used url: %s\n", ykclient_get_last_url (ykc)); assert(ret == YKCLIENT_REPLAYED_OTP); #else printf ("Test SKIPPED\n"); #endif ykclient_done (&ykc); }
int main (int argc, char *argv[]) { unsigned int client_id; char *token, *url = NULL, *ca = NULL, *api_key = NULL, *cai = NULL; int debug = 0; ykclient_rc ret; ykclient_t *ykc = NULL; parse_args (argc, argv, &client_id, &token, &url, &ca, &cai, &api_key, &debug); if (ca || cai) { ret = ykclient_init (&ykc); if (ret != YKCLIENT_OK) return EXIT_FAILURE; } if (ca) { ykclient_set_ca_path (ykc, ca); } if (cai) { ykclient_set_ca_info (ykc, cai); } if (debug) { fprintf (stderr, "Input:\n"); if (url) fprintf (stderr, " validation URL: %s\n", url); if (ca) fprintf (stderr, " CA Path: %s\n", ca); if (cai) fprintf (stderr, " CA Info: %s\n", cai); fprintf (stderr, " client id: %d\n", client_id); fprintf (stderr, " token: %s\n", token); if (api_key != NULL) fprintf (stderr, " api key: %s\n", api_key); } ret = ykclient_verify_otp_v2 (ykc, token, client_id, NULL, 1, (const char **) &url, api_key); if (debug) printf ("Verification output (%d): %s\n", ret, ykclient_strerror (ret)); if (ret == YKCLIENT_REPLAYED_OTP) return 2; else if (ret != YKCLIENT_OK) return 3; return EXIT_SUCCESS; }
virtual EModRet OnLoginAttempt(CSmartPtr<CAuthBase> Auth) { CString const sPassword = Auth->GetPassword(); CUser *pUser = CZNC::Get().FindUser(Auth->GetUsername()); if (pUser && CheckToken(pUser, sPassword.Left(DEFAULT_TOKEN_ID_LEN))) { DEBUG("yubikey: Lookup for " << sPassword.Left(DEFAULT_TOKEN_ID_LEN)); // The following call is blocking. //int result = ykclient_verify_otp(sPassword.c_str(), CLIENT_ID, NULL); int result = ykclient_verify_otp_v2(NULL, sPassword.c_str(), CLIENT_ID, NULL, 0, NULL, NULL); DEBUG("yubikey: " << ykclient_strerror(result)); if (result == YKCLIENT_OK) { Auth->AcceptLogin(*pUser); } else { Auth->RefuseLogin(ykclient_strerror(result)); } return HALT; } return CONTINUE; }
rlm_rcode_t rlm_yubikey_validate(rlm_yubikey_t *inst, REQUEST *request, char const *passcode) { rlm_rcode_t rcode = RLM_MODULE_OK; ykclient_rc status; ykclient_handle_t *yandle; yandle = fr_connection_get(inst->pool); if (!yandle) return RLM_MODULE_FAIL; /* * The libcurl multi-handle interface will tear down the TCP sockets for any partially completed * requests when their easy handle is removed from the multistack. * * For performance reasons ykclient will stop processing the request immediately after receiving * a response from one of the servers. If we then immediately call ykclient_handle_cleanup * the connections are destroyed and will need to be re-established the next time the handle * is used. * * To try and prevent this from happening, we leave cleanup until the *next* time * the handle is used, by which time the requests will of hopefully completed and the connections * can be re-used. * */ ykclient_handle_cleanup(yandle); status = ykclient_request_process(inst->ykc, yandle, passcode); if (status != YKCLIENT_OK) { REDEBUG("%s", ykclient_strerror(status)); switch (status) { case YKCLIENT_BAD_OTP: case YKCLIENT_REPLAYED_OTP: rcode = RLM_MODULE_REJECT; break; case YKCLIENT_NO_SUCH_CLIENT: rcode = RLM_MODULE_NOTFOUND; break; default: rcode = RLM_MODULE_FAIL; } } fr_connection_release(inst->pool, yandle); return rcode; }
/** Creates a new connection handle for use by the FR connection API. * * Matches the fr_connection_create_t function prototype, is passed to * fr_connection_pool_init, and called when a new connection is required by the * connection pool API. * * @see fr_connection_pool_init * @see fr_connection_create_t * @see connection.c */ static void *mod_conn_create(TALLOC_CTX *ctx, void *instance, UNUSED struct timeval const *timeout) { rlm_yubikey_t *inst = instance; ykclient_rc status; ykclient_handle_t *yandle, **marker; status = ykclient_handle_init(inst->ykc, &yandle); if (status != YKCLIENT_OK) { ERROR("rlm_yubikey (%s): %s", inst->name, ykclient_strerror(status)); return NULL; } marker = talloc(ctx, ykclient_handle_t *); talloc_set_destructor(marker, _mod_conn_free); *marker = yandle; return yandle; }
PAM_EXTERN int pam_sm_authenticate (pam_handle_t * pamh, int flags, int argc, const char **argv) { int retval, rc; const char *user = NULL; const char *password = NULL; char otp[MAX_TOKEN_ID_LEN + TOKEN_OTP_LEN + 1] = { 0 }; char otp_id[MAX_TOKEN_ID_LEN + 1] = { 0 }; int password_len = 0; int skip_bytes = 0; int valid_token = 0; struct pam_conv *conv; struct pam_message *pmsg[1], msg[1]; struct pam_response *resp; int nargs = 1; ykclient_t *ykc = NULL; struct cfg cfg_st; struct cfg *cfg = &cfg_st; /* for DBG macro */ parse_cfg (flags, argc, argv, cfg); retval = pam_get_user (pamh, &user, NULL); if (retval != PAM_SUCCESS) { DBG (("get user returned error: %s", pam_strerror (pamh, retval))); goto done; } DBG (("get user returned: %s", user)); if (cfg->mode == CHRESP) { #if HAVE_LIBYKPERS_1 return do_challenge_response(pamh, cfg, user); #else DBG (("no support for challenge/response")); retval = PAM_AUTH_ERR; goto done; #endif } if (cfg->try_first_pass || cfg->use_first_pass) { retval = pam_get_item (pamh, PAM_AUTHTOK, (const void **) &password); if (retval != PAM_SUCCESS) { DBG (("get password returned error: %s", pam_strerror (pamh, retval))); goto done; } DBG (("get password returned: %s", password)); } if (cfg->use_first_pass && password == NULL) { DBG (("use_first_pass set and no password, giving up")); retval = PAM_AUTH_ERR; goto done; } rc = ykclient_init (&ykc); if (rc != YKCLIENT_OK) { DBG (("ykclient_init() failed (%d): %s", rc, ykclient_strerror (rc))); retval = PAM_AUTHINFO_UNAVAIL; goto done; } rc = ykclient_set_client_b64 (ykc, cfg->client_id, cfg->client_key); if (rc != YKCLIENT_OK) { DBG (("ykclient_set_client_b64() failed (%d): %s", rc, ykclient_strerror (rc))); retval = PAM_AUTHINFO_UNAVAIL; goto done; } if (cfg->capath) ykclient_set_ca_path (ykc, cfg->capath); if (cfg->url) ykclient_set_url_template (ykc, cfg->url); if (password == NULL) { retval = pam_get_item (pamh, PAM_CONV, (const void **) &conv); if (retval != PAM_SUCCESS) { DBG (("get conv returned error: %s", pam_strerror (pamh, retval))); goto done; } pmsg[0] = &msg[0]; { const char *query_template = "Yubikey for `%s': "; size_t len = strlen (query_template) + strlen (user); size_t wrote; msg[0].msg = malloc (len); if (!msg[0].msg) { retval = PAM_BUF_ERR; goto done; } wrote = snprintf ((char *) msg[0].msg, len, query_template, user); if (wrote < 0 || wrote >= len) { retval = PAM_BUF_ERR; goto done; } } msg[0].msg_style = cfg->verbose_otp ? PAM_PROMPT_ECHO_ON : PAM_PROMPT_ECHO_OFF; resp = NULL; retval = conv->conv (nargs, (const struct pam_message **) pmsg, &resp, conv->appdata_ptr); free ((char *) msg[0].msg); if (retval != PAM_SUCCESS) { DBG (("conv returned error: %s", pam_strerror (pamh, retval))); goto done; } if (resp->resp == NULL) { DBG (("conv returned NULL passwd?")); goto done; } DBG (("conv returned %i bytes", strlen(resp->resp))); password = resp->resp; } password_len = strlen (password); if (password_len < (cfg->token_id_length + TOKEN_OTP_LEN)) { DBG (("OTP too short to be considered : %i < %i", password_len, (cfg->token_id_length + TOKEN_OTP_LEN))); retval = PAM_AUTH_ERR; goto done; } /* In case the input was systempassword+YubiKeyOTP, we want to skip over "systempassword" when copying the token_id and OTP to separate buffers */ skip_bytes = password_len - (cfg->token_id_length + TOKEN_OTP_LEN); DBG (("Skipping first %i bytes. Length is %i, token_id set to %i and token OTP always %i.", skip_bytes, password_len, cfg->token_id_length, TOKEN_OTP_LEN)); /* Copy full YubiKey output (public ID + OTP) into otp */ strncpy (otp, password + skip_bytes, sizeof (otp) - 1); /* Copy only public ID into otp_id. Destination buffer is zeroed. */ strncpy (otp_id, password + skip_bytes, cfg->token_id_length); DBG (("OTP: %s ID: %s ", otp, otp_id)); /* user entered their system password followed by generated OTP? */ if (password_len > TOKEN_OTP_LEN + cfg->token_id_length) { char *onlypasswd = strdup (password); onlypasswd[password_len - (TOKEN_OTP_LEN + cfg->token_id_length)] = '\0'; DBG (("Extracted a probable system password entered before the OTP - " "setting item PAM_AUTHTOK")); retval = pam_set_item (pamh, PAM_AUTHTOK, onlypasswd); free (onlypasswd); if (retval != PAM_SUCCESS) { DBG (("set_item returned error: %s", pam_strerror (pamh, retval))); goto done; } } else password = NULL; rc = ykclient_request (ykc, otp); DBG (("ykclient return value (%d): %s", rc, ykclient_strerror (rc))); switch (rc) { case YKCLIENT_OK: break; case YKCLIENT_BAD_OTP: case YKCLIENT_REPLAYED_OTP: retval = PAM_AUTH_ERR; goto done; default: retval = PAM_AUTHINFO_UNAVAIL; goto done; } /* authorize the user with supplied token id */ if (cfg->ldapserver != NULL || cfg->ldap_uri != NULL) valid_token = authorize_user_token_ldap (cfg, user, otp_id); else valid_token = authorize_user_token (cfg, user, otp_id); if (valid_token == 0) { DBG (("Yubikey not authorized to login as user")); retval = PAM_AUTHINFO_UNAVAIL; goto done; } retval = PAM_SUCCESS; done: if (ykc) ykclient_done (&ykc); if (cfg->alwaysok && retval != PAM_SUCCESS) { DBG (("alwaysok needed (otherwise return with %d)", retval)); retval = PAM_SUCCESS; } DBG (("done. [%s]", pam_strerror (pamh, retval))); pam_set_data (pamh, "yubico_setcred_return", (void*) (intptr_t) retval, NULL); return retval; }
int rlm_yubikey_ykclient_init(CONF_SECTION *conf, rlm_yubikey_t *inst) { ykclient_rc status; CONF_SECTION *servers; char prefix[100]; int count = 0; if (!inst->client_id) { ERROR("rlm_yubikey (%s): validation.client_id must be set (to a valid id) when validation is enabled", inst->name); return -1; } if (!inst->api_key || !*inst->api_key || is_zero(inst->api_key)) { ERROR("rlm_yubikey (%s): validation.api_key must be set (to a valid key) when validation is enabled", inst->name); return -1; } DEBUG("rlm_yubikey (%s): Initialising ykclient", inst->name); status = ykclient_global_init(); if (status != YKCLIENT_OK) { yk_error: ERROR("rlm_yubikey (%s): %s", ykclient_strerror(status), inst->name); return -1; } status = ykclient_init(&inst->ykc); if (status != YKCLIENT_OK) { goto yk_error; } servers = cf_section_sub_find(conf, "servers"); if (servers) { CONF_PAIR *uri, *first; /* * If there were no uris configured we just use the default * ykclient uris which point to the yubico servers. */ first = uri = cf_pair_find(servers, "uri"); if (!uri) { goto init; } while (uri) { count++; uri = cf_pair_find_next(servers, uri, "uri"); } inst->uris = talloc_zero_array(inst, char const *, count); uri = first; count = 0; while (uri) { inst->uris[count++] = cf_pair_value(uri); uri = cf_pair_find_next(servers, uri, "uri"); } if (count) { status = ykclient_set_url_templates(inst->ykc, count, inst->uris); if (status != YKCLIENT_OK) { goto yk_error; } } } init: status = ykclient_set_client_b64(inst->ykc, inst->client_id, inst->api_key); if (status != YKCLIENT_OK) { ERROR("rlm_yubikey (%s): Failed setting API credentials: %s", ykclient_strerror(status), inst->name); return -1; } snprintf(prefix, sizeof(prefix), "rlm_yubikey (%s)", inst->name); inst->pool = module_connection_pool_init(conf, inst, mod_conn_create, NULL, prefix); if (!inst->pool) { ykclient_done(&inst->ykc); return -1; } return 0; }
int main (void) { int client_id = 1851; char client_key[] = { 0xa0, 0x15, 0x5b, 0x36, 0xde, 0xc8, 0x65, 0xe8, 0x59, 0x19, 0x1f, 0x7d, 0xae, 0xfa, 0xbc, 0x77, 0xa4, 0x59, 0xd4, 0x33 }; char *client_hexkey = "a0155b36dec865e859191f7daefabc77a459d433"; char *client_b64key = "oBVbNt7IZehZGR99rvq8d6RZ1DM="; ykclient_t *ykc; int ret; curl_global_init(CURL_GLOBAL_ALL); TEST(("init self")); ret = ykclient_init (&ykc); printf ("ykclient_init (%d): %s\n", ret, ykclient_strerror (ret)); assert(ret == YKCLIENT_OK); TEST(("null client_id, expect REPLAYED_OTP")); ykclient_set_verify_signature(ykc, 0); ykclient_set_client (ykc, client_id, 0, NULL); #ifndef TEST_WITHOUT_INTERNET ret = ykclient_request (ykc, "dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh"); printf ("ykclient_request (%d): %s\n", ret, ykclient_strerror (ret)); printf ("used url: %s\n", ykclient_get_last_url (ykc)); assert(ret == YKCLIENT_REPLAYED_OTP); #else printf ("Test SKIPPED\n"); #endif TEST(("client_id set(20), correct client_key, expect REPLAYED_OTP")); ykclient_set_client (ykc, client_id, 20, client_key); #ifndef TEST_WITHOUT_INTERNET ret = ykclient_request (ykc, "dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh"); printf ("ykclient_request (%d): %s\n", ret, ykclient_strerror (ret)); printf ("used url: %s\n", ykclient_get_last_url (ykc)); assert (ret == YKCLIENT_REPLAYED_OTP); #else printf ("Test SKIPPED\n"); #endif TEST(("wrong client_id set(10), correct client_key, expect BAD_SIGNATURE")); ykclient_set_client (ykc, client_id, 10, client_key); #ifndef TEST_WITHOUT_INTERNET ret = ykclient_request (ykc, "dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh"); printf ("ykclient_request (%d): %s\n", ret, ykclient_strerror (ret)); printf ("used url: %s\n", ykclient_get_last_url (ykc)); assert (ret == YKCLIENT_BAD_SIGNATURE); #else printf ("Test SKIPPED\n"); #endif TEST(("invalid client_id set(a), correct client_key, expect HEX_DECODE_ERROR")); ret = ykclient_set_client_hex (ykc, client_id, "a"); printf ("ykclient_set_client_hex (%d): %s\n", ret, ykclient_strerror (ret)); assert (ret == YKCLIENT_HEX_DECODE_ERROR); TEST(("invalid client_id set(xx), correct client_key, expect HEX_DECODE_ERROR")); ret = ykclient_set_client_hex (ykc, client_id, "xx"); printf ("ykclient_set_client_hex (%d): %s\n", ret, ykclient_strerror (ret)); assert (ret == YKCLIENT_HEX_DECODE_ERROR); TEST(("hex client_id set, correct client_key, expect OK")); ret = ykclient_set_client_hex (ykc, client_id, client_hexkey); printf ("ykclient_set_client_hex (%d): %s\n", ret, ykclient_strerror (ret)); assert (ret == YKCLIENT_OK); #ifndef TEST_WITHOUT_INTERNET TEST(("validation request, expect REPLAYED_OTP")); ret = ykclient_request (ykc, "dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh"); printf ("ykclient_request (%d): %s\n", ret, ykclient_strerror (ret)); printf ("used url: %s\n", ykclient_get_last_url (ykc)); assert (ret == YKCLIENT_REPLAYED_OTP); #else printf ("Test SKIPPED\n"); #endif TEST(("set deadbeef client_id, expect OK")); ret = ykclient_set_client_hex (ykc, client_id, "deadbeef"); printf ("ykclient_set_client_hex (%d): %s\n", ret, ykclient_strerror (ret)); assert (ret == YKCLIENT_OK); #ifndef TEST_WITHOUT_INTERNET TEST(("validation request, expect BAD_SIGNATURE")); ret = ykclient_request (ykc, "dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh"); printf ("ykclient_request (%d): %s\n", ret, ykclient_strerror (ret)); printf ("used url: %s\n", ykclient_get_last_url (ykc)); assert (ret == YKCLIENT_BAD_SIGNATURE); #else printf ("Test SKIPPED\n"); #endif TEST(("b64 set deadbeef client_id, expect OK")); ret = ykclient_set_client_b64 (ykc, client_id, "deadbeef"); printf ("ykclient_set_client_b64 (%d): %s\n", ret, ykclient_strerror (ret)); assert (ret == YKCLIENT_OK); #ifndef TEST_WITHOUT_INTERNET /* When the server dislikes our signature, it will sign the response with a NULL key, so the API call will fail with BAD_SERVER_SIGNATURE even though the server returned status=BAD_SIGNATURE. */ TEST(("validation request, expect BAD_SERVER_SIGNATURE")); ret = ykclient_request (ykc, "dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh"); printf ("ykclient_request (%d): %s\n", ret, ykclient_strerror (ret)); printf ("used url: %s\n", ykclient_get_last_url (ykc)); assert (ret == YKCLIENT_BAD_SERVER_SIGNATURE); #else printf ("Test SKIPPED\n"); #endif #ifndef TEST_WITHOUT_INTERNET /* Now, disable our checking of the servers signature to get the error the server returned (server will use 00000 as key when signing this error response). */ TEST(("validation request, expect BAD_SIGNATURE")); ykclient_set_verify_signature (ykc, 0); ret = ykclient_request (ykc, "dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh"); printf ("ykclient_request (%d): %s\n", ret, ykclient_strerror (ret)); printf ("used url: %s\n", ykclient_get_last_url (ykc)); assert (ret == YKCLIENT_BAD_SIGNATURE); #else printf ("Test SKIPPED\n"); #endif TEST(("b64 set client_b64key, expect OK")); ret = ykclient_set_client_b64 (ykc, client_id, client_b64key); printf ("ykclient_set_client_b64 (%d): %s\n", ret, ykclient_strerror (ret)); assert (ret == YKCLIENT_OK); #ifndef TEST_WITHOUT_INTERNET TEST(("validation request, expect REPLAYED_OTP")); ret = ykclient_request (ykc, "dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh"); printf ("ykclient_request (%d): %s\n", ret, ykclient_strerror (ret)); printf ("used url: %s\n", ykclient_get_last_url (ykc)); assert (ret == YKCLIENT_REPLAYED_OTP); #else printf ("Test SKIPPED\n"); #endif TEST(("set WS 2.0 URL template")); /* Set one URL and run tests with that. */ ykclient_set_url_template (ykc, "http://api.yubico.com/wsapi/2.0/verify?id=%d&otp=%s"); #ifndef TEST_WITHOUT_INTERNET TEST(("validation request, expect REPLAYED_OTP")); ret = ykclient_request (ykc, "dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh"); printf ("yubikey_request (%d): %s\n", ret, ykclient_strerror (ret)); printf ("used url: %s\n", ykclient_get_last_url (ykc)); assert (ret == YKCLIENT_REPLAYED_OTP); #else printf ("Test SKIPPED\n"); #endif ykclient_set_verify_signature(ykc, 1); TEST(("validation request with valid signature, expect REPLAYED_OTP")); // Check a genuine signature. ykclient_set_client (ykc, client_id, 20, client_key); #ifndef TEST_WITHOUT_INTERNET ret = ykclient_request (ykc, "dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh"); printf ("ykclient_request (%d): %s\n", ret, ykclient_strerror (ret)); printf ("used url: %s\n", ykclient_get_last_url (ykc)); assert (ret == YKCLIENT_REPLAYED_OTP); #else printf ("Test SKIPPED\n"); #endif TEST(("validation request with bad key, expect YKCLIENT_BAD_SERVER_SIGNATURE")); // Check a genuine signature with a truncated key. ykclient_set_client (ykc, client_id, 10, client_key); #ifndef TEST_WITHOUT_INTERNET ret = ykclient_request (ykc, "dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh"); printf ("ykclient_request (%d): %s\n", ret, ykclient_strerror (ret)); printf ("used url: %s\n", ykclient_get_last_url (ykc)); assert (ret == YKCLIENT_BAD_SERVER_SIGNATURE); #else printf ("Test SKIPPED\n"); #endif TEST(("Set and use several V2.0 URLs")); const char *templates[] = { "http://api.yubico.com/wsapi/2.0/verify?id=%d&otp=%s", "http://api2.yubico.com/wsapi/2.0/verify?id=%d&otp=%s", "http://api3.yubico.com/wsapi/2.0/verify?id=%d&otp=%s", "http://api4.yubico.com/wsapi/2.0/verify?id=%d&otp=%s", "http://api5.yubico.com/wsapi/2.0/verify?id=%d&otp=%s", }; ykclient_set_url_templates(ykc, 5, templates); ykclient_set_client (ykc, client_id, 20, client_key); #ifndef TEST_WITHOUT_INTERNET ret = ykclient_request (ykc, "dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh"); printf ("ykclient_request (%d): %s\n", ret, ykclient_strerror (ret)); printf ("used url: %s\n", ykclient_get_last_url (ykc)); assert (ret == YKCLIENT_REPLAYED_OTP); #else printf ("Test SKIPPED\n"); #endif ykclient_done (&ykc); TEST(("strerror 0")); printf ("strerror(0): %s\n", ykclient_strerror (0)); ret = strcmp(ykclient_strerror (0), "Success"); assert (ret == 0); TEST(("strerror BAD_OTP")); printf ("strerror(BAD_OTP): %s\n", ykclient_strerror (YKCLIENT_BAD_OTP)); ret = strcmp(ykclient_strerror (YKCLIENT_BAD_OTP), "Yubikey OTP was bad (BAD_OTP)"); assert (ret == 0); test_v1_validation(client_id, client_b64key); test_base64(); test_hmac(); printf ("All tests passed\n"); curl_global_cleanup(); return 0; }