int do_manual_authentication(const cfg_t *cfg, const device_t *devices, const unsigned n_devs, pam_handle_t *pamh) { u2fs_ctx_t *ctx_arr[n_devs]; u2fs_auth_res_t *auth_result; u2fs_rc s_rc; char *response = NULL; char prompt[MAX_PROMPT_LEN]; char *buf; int retval = -2; unsigned i = 0; if (u2fs_global_init(0) != U2FS_OK) { if (cfg->debug) D(cfg->debug_file, "Unable to initialize libu2f-server"); return retval; } for (i = 0; i < n_devs; ++i) { if (u2fs_init(ctx_arr + i) != U2FS_OK) { if (cfg->debug) D(cfg->debug_file, "Unable to initialize libu2f-server"); return retval; } if ((s_rc = u2fs_set_origin(ctx_arr[i], cfg->origin)) != U2FS_OK) { if (cfg->debug) D(cfg->debug_file, "Unable to set origin: %s", u2fs_strerror(s_rc)); return retval; } if ((s_rc = u2fs_set_appid(ctx_arr[i], cfg->appid)) != U2FS_OK) { if (cfg->debug) D(cfg->debug_file, "Unable to set appid: %s", u2fs_strerror(s_rc)); return retval; } if (cfg->debug) D(cfg->debug_file, "Attempting authentication with device number %d", i + 1); if ((s_rc = u2fs_set_keyHandle(ctx_arr[i], devices[i].keyHandle)) != U2FS_OK) { if (cfg->debug) D(cfg->debug_file, "Unable to set keyHandle: %s", u2fs_strerror(s_rc)); return retval; } if ((s_rc = u2fs_set_publicKey(ctx_arr[i], devices[i].publicKey)) != U2FS_OK) { if (cfg->debug) D(cfg->debug_file, "Unable to set publicKey %s", u2fs_strerror(s_rc)); return retval; } if ((s_rc = u2fs_authentication_challenge(ctx_arr[i], &buf)) != U2FS_OK) { if (cfg->debug) D(cfg->debug_file, "Unable to produce authentication challenge: %s", u2fs_strerror(s_rc)); return retval; } if (cfg->debug) D(cfg->debug_file, "Challenge: %s", buf); if (i == 0) { snprintf(prompt, sizeof(prompt), "Now please copy-paste the below challenge(s) to " "'u2f-host -aauthenticate -o %s'", cfg->origin); converse(pamh, PAM_TEXT_INFO, prompt); } converse(pamh, PAM_TEXT_INFO, buf); free(buf); buf = NULL; } converse(pamh, PAM_TEXT_INFO, "Now, please enter the response(s) below, one per line."); retval = -1; for (i = 0; i < n_devs; ++i) { snprintf(prompt, sizeof(prompt), "[%d]: ", i); response = converse(pamh, PAM_PROMPT_ECHO_ON, prompt); converse(pamh, PAM_TEXT_INFO, response); s_rc = u2fs_authentication_verify(ctx_arr[i], response, &auth_result); u2fs_free_auth_res(auth_result); if (s_rc == U2FS_OK) { retval = 1; } free(response); if (retval == 1) { break; } } for (i = 0; i < n_devs; ++i) u2fs_done(ctx_arr[i]); u2fs_global_done(); return retval; }
int main(int argc, char *argv[]) { int exit_code = EXIT_FAILURE; struct gengetopt_args_info args_info; char buf[BUFSIZE]; char *p; char *response; u2fs_ctx_t *ctx; u2fs_reg_res_t *reg_result; u2fs_rc s_rc; u2fh_rc h_rc; char *origin = NULL; char *appid = NULL; char *user = NULL; const char *kh = NULL; const char *pk = NULL; u2fh_devs *devs = NULL; unsigned i; unsigned max_index = 0; if (cmdline_parser(argc, argv, &args_info) != 0) exit(EXIT_FAILURE); if (args_info.help_given) { cmdline_parser_print_help(); printf ("\nReport bugs at <https://github.com/Yubico/libu2f-server>.\n"); exit(EXIT_SUCCESS); } s_rc = u2fs_global_init(args_info.debug_flag ? U2FS_DEBUG : 0); if (s_rc != U2FS_OK) { fprintf(stderr, "error: u2fs_global_init (%d): %s\n", s_rc, u2fs_strerror(s_rc)); exit(EXIT_FAILURE); } s_rc = u2fs_init(&ctx); if (s_rc != U2FS_OK) { fprintf(stderr, "error: u2fs_init (%d): %s\n", s_rc, u2fs_strerror(s_rc)); exit(EXIT_FAILURE); } if (args_info.origin_given) origin = args_info.origin_arg; else { if (!strcpy(buf, PAM_PREFIX)) fprintf(stderr, "strcpy failed\n"); if (gethostname(buf + strlen(PAM_PREFIX), BUFSIZE - strlen(PAM_PREFIX)) == -1) { perror("gethostname"); exit(EXIT_FAILURE); } origin = buf; } s_rc = u2fs_set_origin(ctx, origin); if (s_rc != U2FS_OK) { printf("error: u2fs_set_origin (%d): %s\n", s_rc, u2fs_strerror(s_rc)); exit(EXIT_FAILURE); } if (args_info.appid_given) appid = args_info.appid_arg; else { if (args_info.origin_given) { if (!strcpy(buf, PAM_PREFIX)) fprintf(stderr, "strcpy failed\n"); if (gethostname (buf + strlen(PAM_PREFIX), BUFSIZE - strlen(PAM_PREFIX)) == -1) { perror("gethostname"); exit(EXIT_FAILURE); } } appid = buf; } s_rc = u2fs_set_appid(ctx, appid); if (s_rc != U2FS_OK) { fprintf(stderr, "error: u2fs_set_appid (%d): %s\n", s_rc, u2fs_strerror(s_rc)); exit(EXIT_FAILURE); } if (args_info.username_given) user = args_info.username_arg; else { user = getlogin(); if (!user) { perror("getlogin"); exit(EXIT_FAILURE); } } if (u2fh_global_init(args_info.debug_flag ? U2FS_DEBUG : 0) != U2FH_OK || u2fh_devs_init(&devs) != U2FH_OK) { fprintf(stderr, "Unable to initialize libu2f-host"); exit(EXIT_FAILURE); } h_rc = u2fh_devs_discover(devs, &max_index); if (h_rc != U2FH_OK && h_rc != U2FH_NO_U2F_DEVICE) { fprintf(stderr, "Unable to discover device(s), %s (%d)", u2fh_strerror(h_rc), h_rc); exit(EXIT_FAILURE); } if (h_rc == U2FH_NO_U2F_DEVICE) { for (i = 0; i < TIMEOUT; i += FREQUENCY) { fprintf(stderr, "\rNo U2F device available, please insert one now, you have %2d seconds", TIMEOUT - i); fflush(stderr); sleep(FREQUENCY); h_rc = u2fh_devs_discover(devs, &max_index); if (h_rc == U2FH_OK) { fprintf(stderr, "\nDevice found!\n"); break; } if (h_rc != U2FH_NO_U2F_DEVICE) { fprintf(stderr, "\nUnable to discover device(s), %s (%d)", u2fh_strerror(h_rc), h_rc); exit(EXIT_FAILURE); } } } if (h_rc != U2FH_OK) { fprintf(stderr, "\rNo device found. Aborting. \n"); exit(EXIT_FAILURE); } s_rc = u2fs_registration_challenge(ctx, &p); if (s_rc != U2FS_OK) { fprintf(stderr, "Unable to generate registration challenge, %s (%d)", u2fs_strerror(s_rc), s_rc); exit(EXIT_FAILURE); } h_rc = u2fh_register(devs, p, origin, &response, U2FH_REQUEST_USER_PRESENCE); if (s_rc != U2FS_OK) { fprintf(stderr, "Unable to generate registration challenge, %s (%d)", u2fs_strerror(s_rc), s_rc); exit(EXIT_FAILURE); } s_rc = u2fs_registration_verify(ctx, response, ®_result); if (s_rc != U2FS_OK) { fprintf(stderr, "error: (%d) %s\n", s_rc, u2fs_strerror(s_rc)); exit(EXIT_FAILURE); } kh = u2fs_get_registration_keyHandle(reg_result); if (!kh) { fprintf(stderr, "Unable to extract keyHandle: (%d) %s\n", s_rc, u2fs_strerror(s_rc)); exit(EXIT_FAILURE); } pk = u2fs_get_registration_publicKey(reg_result); if (!pk) { fprintf(stderr, "Unable to extract public key: (%d) %s\n", s_rc, u2fs_strerror(s_rc)); exit(EXIT_FAILURE); } if (!args_info.nouser_given) printf("%s", user); printf(":%s,", kh); for (i = 0; i < U2FS_PUBLIC_KEY_LEN; i++) { printf("%02x", pk[i] & 0xFF); } exit_code = EXIT_SUCCESS; u2fs_done(ctx); u2fs_global_done(); exit(exit_code); }
int do_authentication(const cfg_t *cfg, const device_t *devices, const unsigned n_devs, pam_handle_t *pamh) { u2fs_ctx_t *ctx; u2fs_auth_res_t *auth_result; u2fs_rc s_rc; u2fh_rc h_rc; u2fh_devs *devs = NULL; char *response = NULL; char *buf; int retval = -2; int cued = 0; unsigned i = 0; unsigned max_index = 0; unsigned max_index_prev = 0; h_rc = u2fh_global_init(cfg->debug ? U2FH_DEBUG : 0); if (h_rc != U2FH_OK) { D(cfg->debug_file, "Unable to initialize libu2f-host: %s", u2fh_strerror(h_rc)); return retval; } h_rc = u2fh_devs_init(&devs); if (h_rc != U2FH_OK) { D(cfg->debug_file, "Unable to initialize libu2f-host device handles: %s", u2fh_strerror(h_rc)); return retval; } if ((h_rc = u2fh_devs_discover(devs, &max_index)) != U2FH_OK) { if (cfg->debug) D(cfg->debug_file, "Unable to discover device(s), %s", u2fh_strerror(h_rc)); return retval; } max_index_prev = max_index; if (cfg->debug) D(cfg->debug_file, "Device max index is %u", max_index); s_rc = u2fs_global_init(cfg->debug ? U2FS_DEBUG : 0); if (s_rc != U2FS_OK) { D(cfg->debug_file, "Unable to initialize libu2f-server: %s", u2fs_strerror(s_rc)); return retval; } s_rc = u2fs_init(&ctx); if (s_rc != U2FS_OK) { D(cfg->debug_file, "Unable to initialize libu2f-server context: %s", u2fs_strerror(s_rc)); return retval; } if ((s_rc = u2fs_set_origin(ctx, cfg->origin)) != U2FS_OK) { if (cfg->debug) D(cfg->debug_file, "Unable to set origin: %s", u2fs_strerror(s_rc)); return retval; } if ((s_rc = u2fs_set_appid(ctx, cfg->appid)) != U2FS_OK) { if (cfg->debug) D(cfg->debug_file, "Unable to set appid: %s", u2fs_strerror(s_rc)); return retval; } if (cfg->nodetect && cfg->debug) D(cfg->debug_file, "nodetect option specified, suitable key detection will be skipped"); i = 0; while (i < n_devs) { retval = -2; if (cfg->debug) D(cfg->debug_file, "Attempting authentication with device number %d", i + 1); if ((s_rc = u2fs_set_keyHandle(ctx, devices[i].keyHandle)) != U2FS_OK) { if (cfg->debug) D(cfg->debug_file, "Unable to set keyHandle: %s", u2fs_strerror(s_rc)); return retval; } if ((s_rc = u2fs_set_publicKey(ctx, devices[i].publicKey)) != U2FS_OK) { if (cfg->debug) D(cfg->debug_file, "Unable to set publicKey %s", u2fs_strerror(s_rc)); return retval; } if ((s_rc = u2fs_authentication_challenge(ctx, &buf)) != U2FS_OK) { if (cfg->debug) D(cfg->debug_file, "Unable to produce authentication challenge: %s", u2fs_strerror(s_rc)); free(buf); buf = NULL; return retval; } if (cfg->debug) D(cfg->debug_file, "Challenge: %s", buf); if (cfg->nodetect || (h_rc = u2fh_authenticate(devs, buf, cfg->origin, &response, 0)) == U2FH_OK ) { if (cfg->manual == 0 && cfg->cue && !cued) { cued = 1; converse(pamh, PAM_TEXT_INFO, DEFAULT_CUE); } retval = -1; if ((h_rc = u2fh_authenticate(devs, buf, cfg->origin, &response, U2FH_REQUEST_USER_PRESENCE)) == U2FH_OK) { if (cfg->debug) D(cfg->debug_file, "Response: %s", response); s_rc = u2fs_authentication_verify(ctx, response, &auth_result); u2fs_free_auth_res(auth_result); free(response); response = NULL; if (s_rc == U2FS_OK) { retval = 1; free(buf); buf = NULL; break; } } else { if (cfg->debug) D(cfg->debug_file, "Unable to communicate to the device, %s", u2fh_strerror(h_rc)); } } else { if (cfg->debug) D(cfg->debug_file, "Device for this keyhandle is not present."); } free(buf); buf = NULL; i++; if (u2fh_devs_discover(devs, &max_index) != U2FH_OK) { if (cfg->debug) D(cfg->debug_file, "Unable to discover devices"); return retval; } if (max_index > max_index_prev) { if (cfg->debug) D(cfg->debug_file, "Devices max_index has changed: %u (was %u). Starting over", max_index, max_index_prev); max_index_prev = max_index; i = 0; } } u2fh_devs_done(devs); u2fh_global_done(); u2fs_done(ctx); u2fs_global_done(); return retval; }