bool get_user_pass_cr (struct user_pass *up, const char *auth_file, const char *prefix, const unsigned int flags, const char *auth_challenge) { struct gc_arena gc = gc_new (); if (!up->defined) { const bool from_stdin = (!auth_file || !strcmp (auth_file, "stdin")); if (flags & GET_USER_PASS_PREVIOUS_CREDS_FAILED) msg (M_WARN, "Note: previous '%s' credentials failed", prefix); #ifdef ENABLE_MANAGEMENT /* * Get username/password from management interface? */ if (management && ((auth_file && streq (auth_file, "management")) || (from_stdin && (flags & GET_USER_PASS_MANAGEMENT))) && management_query_user_pass_enabled (management)) { const char *sc = NULL; if (flags & GET_USER_PASS_PREVIOUS_CREDS_FAILED) management_auth_failure (management, prefix, "previous auth credentials failed"); #ifdef ENABLE_CLIENT_CR if (auth_challenge && (flags & GET_USER_PASS_STATIC_CHALLENGE)) sc = auth_challenge; #endif if (!management_query_user_pass (management, up, prefix, flags, sc)) { if ((flags & GET_USER_PASS_NOFATAL) != 0) return false; else msg (M_FATAL, "ERROR: could not read %s username/password/ok/string from management interface", prefix); } } else #endif /* * Get NEED_OK confirmation from the console */ if (flags & GET_USER_PASS_NEED_OK) { struct buffer user_prompt = alloc_buf_gc (128, &gc); buf_printf (&user_prompt, "NEED-OK|%s|%s:", prefix, up->username); if (!get_console_input (BSTR (&user_prompt), true, up->password, USER_PASS_LEN)) msg (M_FATAL, "ERROR: could not read %s ok-confirmation from stdin", prefix); if (!strlen (up->password)) strcpy (up->password, "ok"); } /* * Get username/password from standard input? */ else if (from_stdin) { #ifndef WIN32 /* did we --daemon'ize before asking for passwords? */ if ( !isatty(0) && !isatty(2) ) { msg(M_FATAL, "neither stdin nor stderr are a tty device, can't ask for %s password. If you used --daemon, you need to use --askpass to make passphrase-protected keys work, and you can not use --auth-nocache.", prefix ); } #endif #ifdef ENABLE_CLIENT_CR if (auth_challenge && (flags & GET_USER_PASS_DYNAMIC_CHALLENGE)) { struct auth_challenge_info *ac = get_auth_challenge (auth_challenge, &gc); if (ac) { char *response = (char *) gc_malloc (USER_PASS_LEN, false, &gc); struct buffer packed_resp; buf_set_write (&packed_resp, (uint8_t*)up->password, USER_PASS_LEN); msg (M_INFO|M_NOPREFIX, "CHALLENGE: %s", ac->challenge_text); if (!get_console_input ("Response:", BOOL_CAST(ac->flags&CR_ECHO), response, USER_PASS_LEN)) msg (M_FATAL, "ERROR: could not read challenge response from stdin"); strncpynt (up->username, ac->user, USER_PASS_LEN); buf_printf (&packed_resp, "CRV1::%s::%s", ac->state_id, response); } else { msg (M_FATAL, "ERROR: received malformed challenge request from server"); } } else #endif { struct buffer user_prompt = alloc_buf_gc (128, &gc); struct buffer pass_prompt = alloc_buf_gc (128, &gc); buf_printf (&user_prompt, "Enter %s Username:"******"Enter %s Password:"******"ERROR: could not read %s username from stdin", prefix); if (strlen (up->username) == 0) msg (M_FATAL, "ERROR: %s username is empty", prefix); } if (!get_console_input (BSTR (&pass_prompt), false, up->password, USER_PASS_LEN)) msg (M_FATAL, "ERROR: could not not read %s password from stdin", prefix); #ifdef ENABLE_CLIENT_CR if (auth_challenge && (flags & GET_USER_PASS_STATIC_CHALLENGE)) { char *response = (char *) gc_malloc (USER_PASS_LEN, false, &gc); struct buffer packed_resp; char *pw64=NULL, *resp64=NULL; msg (M_INFO|M_NOPREFIX, "CHALLENGE: %s", auth_challenge); if (!get_console_input ("Response:", BOOL_CAST(flags & GET_USER_PASS_STATIC_CHALLENGE_ECHO), response, USER_PASS_LEN)) msg (M_FATAL, "ERROR: could not read static challenge response from stdin"); if (openvpn_base64_encode(up->password, strlen(up->password), &pw64) == -1 || openvpn_base64_encode(response, strlen(response), &resp64) == -1) msg (M_FATAL, "ERROR: could not base64-encode password/static_response"); buf_set_write (&packed_resp, (uint8_t*)up->password, USER_PASS_LEN); buf_printf (&packed_resp, "SCRV1:%s:%s", pw64, resp64); string_clear(pw64); free(pw64); string_clear(resp64); free(resp64); } #endif } } else { /* * Get username/password from a file. */ FILE *fp; #ifndef ENABLE_PASSWORD_SAVE /* * Unless ENABLE_PASSWORD_SAVE is defined, don't allow sensitive passwords * to be read from a file. */ if (flags & GET_USER_PASS_SENSITIVE) msg (M_FATAL, "Sorry, '%s' password cannot be read from a file", prefix); #endif warn_if_group_others_accessible (auth_file); fp = platform_fopen (auth_file, "r"); if (!fp) msg (M_ERR, "Error opening '%s' auth file: %s", prefix, auth_file); if (flags & GET_USER_PASS_PASSWORD_ONLY) { if (fgets (up->password, USER_PASS_LEN, fp) == NULL) msg (M_FATAL, "Error reading password from %s authfile: %s", prefix, auth_file); } else { if (fgets (up->username, USER_PASS_LEN, fp) == NULL || fgets (up->password, USER_PASS_LEN, fp) == NULL) msg (M_FATAL, "Error reading username and password (must be on two consecutive lines) from %s authfile: %s", prefix, auth_file); } fclose (fp); chomp (up->username); chomp (up->password); if (!(flags & GET_USER_PASS_PASSWORD_ONLY) && strlen (up->username) == 0) msg (M_FATAL, "ERROR: username from %s authfile '%s' is empty", prefix, auth_file); } string_mod (up->username, CC_PRINT, CC_CRLF, 0); string_mod (up->password, CC_PRINT, CC_CRLF, 0); up->defined = true; } #if 0 msg (M_INFO, "GET_USER_PASS %s u='%s' p='%s'", prefix, up->username, up->password); #endif gc_free (&gc); return true; }
bool get_user_pass_cr(struct user_pass *up, const char *auth_file, const char *prefix, const unsigned int flags, const char *auth_challenge) { struct gc_arena gc = gc_new(); if (!up->defined) { bool from_authfile = (auth_file && !streq(auth_file, "stdin")); bool username_from_stdin = false; bool password_from_stdin = false; bool response_from_stdin = true; if (flags & GET_USER_PASS_PREVIOUS_CREDS_FAILED) { msg(M_WARN, "Note: previous '%s' credentials failed", prefix); } #ifdef ENABLE_MANAGEMENT /* * Get username/password from management interface? */ if (management && (!from_authfile && (flags & GET_USER_PASS_MANAGEMENT)) && management_query_user_pass_enabled(management)) { const char *sc = NULL; response_from_stdin = false; if (flags & GET_USER_PASS_PREVIOUS_CREDS_FAILED) { management_auth_failure(management, prefix, "previous auth credentials failed"); } #ifdef ENABLE_CLIENT_CR if (auth_challenge && (flags & GET_USER_PASS_STATIC_CHALLENGE)) { sc = auth_challenge; } #endif if (!management_query_user_pass(management, up, prefix, flags, sc)) { if ((flags & GET_USER_PASS_NOFATAL) != 0) { return false; } else { msg(M_FATAL, "ERROR: could not read %s username/password/ok/string from management interface", prefix); } } } else #endif /* ifdef ENABLE_MANAGEMENT */ /* * Get NEED_OK confirmation from the console */ if (flags & GET_USER_PASS_NEED_OK) { struct buffer user_prompt = alloc_buf_gc(128, &gc); buf_printf(&user_prompt, "NEED-OK|%s|%s:", prefix, up->username); if (!query_user_SINGLE(BSTR(&user_prompt), BLEN(&user_prompt), up->password, USER_PASS_LEN, false)) { msg(M_FATAL, "ERROR: could not read %s ok-confirmation from stdin", prefix); } if (!strlen(up->password)) { strcpy(up->password, "ok"); } } else if (flags & GET_USER_PASS_INLINE_CREDS) { struct buffer buf; buf_set_read(&buf, (uint8_t *) auth_file, strlen(auth_file) + 1); if (!(flags & GET_USER_PASS_PASSWORD_ONLY)) { buf_parse(&buf, '\n', up->username, USER_PASS_LEN); } buf_parse(&buf, '\n', up->password, USER_PASS_LEN); } /* * Read from auth file unless this is a dynamic challenge request. */ else if (from_authfile && !(flags & GET_USER_PASS_DYNAMIC_CHALLENGE)) { /* * Try to get username/password from a file. */ FILE *fp; char password_buf[USER_PASS_LEN] = { '\0' }; fp = platform_fopen(auth_file, "r"); if (!fp) { msg(M_ERR, "Error opening '%s' auth file: %s", prefix, auth_file); } if ((flags & GET_USER_PASS_PASSWORD_ONLY) == 0) { /* Read username first */ if (fgets(up->username, USER_PASS_LEN, fp) == NULL) { msg(M_FATAL, "Error reading username from %s authfile: %s", prefix, auth_file); } } chomp(up->username); if (fgets(password_buf, USER_PASS_LEN, fp) != NULL) { chomp(password_buf); } if (flags & GET_USER_PASS_PASSWORD_ONLY && !password_buf[0]) { msg(M_FATAL, "Error reading password from %s authfile: %s", prefix, auth_file); } if (password_buf[0]) { strncpy(up->password, password_buf, USER_PASS_LEN); } else { password_from_stdin = 1; } fclose(fp); if (!(flags & GET_USER_PASS_PASSWORD_ONLY) && strlen(up->username) == 0) { msg(M_FATAL, "ERROR: username from %s authfile '%s' is empty", prefix, auth_file); } } else { username_from_stdin = true; password_from_stdin = true; } /* * Get username/password from standard input? */ if (username_from_stdin || password_from_stdin || response_from_stdin) { #ifdef ENABLE_CLIENT_CR if (auth_challenge && (flags & GET_USER_PASS_DYNAMIC_CHALLENGE) && response_from_stdin) { struct auth_challenge_info *ac = get_auth_challenge(auth_challenge, &gc); if (ac) { char *response = (char *) gc_malloc(USER_PASS_LEN, false, &gc); struct buffer packed_resp, challenge; challenge = alloc_buf_gc(14+strlen(ac->challenge_text), &gc); buf_printf(&challenge, "CHALLENGE: %s", ac->challenge_text); buf_set_write(&packed_resp, (uint8_t *)up->password, USER_PASS_LEN); if (!query_user_SINGLE(BSTR(&challenge), BLEN(&challenge), response, USER_PASS_LEN, BOOL_CAST(ac->flags&CR_ECHO))) { msg(M_FATAL, "ERROR: could not read challenge response from stdin"); } strncpynt(up->username, ac->user, USER_PASS_LEN); buf_printf(&packed_resp, "CRV1::%s::%s", ac->state_id, response); } else { msg(M_FATAL, "ERROR: received malformed challenge request from server"); } } else #endif /* ifdef ENABLE_CLIENT_CR */ { struct buffer user_prompt = alloc_buf_gc(128, &gc); struct buffer pass_prompt = alloc_buf_gc(128, &gc); query_user_clear(); buf_printf(&user_prompt, "Enter %s Username:"******"Enter %s Password:"******"ERROR: Failed retrieving username or password"); } if (!(flags & GET_USER_PASS_PASSWORD_ONLY)) { if (strlen(up->username) == 0) { msg(M_FATAL, "ERROR: %s username is empty", prefix); } } #ifdef ENABLE_CLIENT_CR if (auth_challenge && (flags & GET_USER_PASS_STATIC_CHALLENGE) && response_from_stdin) { char *response = (char *) gc_malloc(USER_PASS_LEN, false, &gc); struct buffer packed_resp, challenge; char *pw64 = NULL, *resp64 = NULL; challenge = alloc_buf_gc(14+strlen(auth_challenge), &gc); buf_printf(&challenge, "CHALLENGE: %s", auth_challenge); if (!query_user_SINGLE(BSTR(&challenge), BLEN(&challenge), response, USER_PASS_LEN, BOOL_CAST(flags & GET_USER_PASS_STATIC_CHALLENGE_ECHO))) { msg(M_FATAL, "ERROR: could not retrieve static challenge response"); } if (openvpn_base64_encode(up->password, strlen(up->password), &pw64) == -1 || openvpn_base64_encode(response, strlen(response), &resp64) == -1) { msg(M_FATAL, "ERROR: could not base64-encode password/static_response"); } buf_set_write(&packed_resp, (uint8_t *)up->password, USER_PASS_LEN); buf_printf(&packed_resp, "SCRV1:%s:%s", pw64, resp64); string_clear(pw64); free(pw64); string_clear(resp64); free(resp64); } #endif /* ifdef ENABLE_CLIENT_CR */ } } string_mod(up->username, CC_PRINT, CC_CRLF, 0); string_mod(up->password, CC_PRINT, CC_CRLF, 0); up->defined = true; } #if 0 msg(M_INFO, "GET_USER_PASS %s u='%s' p='%s'", prefix, up->username, up->password); #endif gc_free(&gc); return true; }