From patchwork Wed Jan 17 21:31:44 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gert Doering X-Patchwork-Id: 3577 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:693c:2b0b:b0:101:b91e:57cc with SMTP id ro11csp205720dyc; Wed, 17 Jan 2024 13:32:28 -0800 (PST) X-Google-Smtp-Source: AGHT+IGLtdY/MdcGVZ7tj6Cyrw1HCWBz1RkmHFKG6E5pJBcjZIwFr+zylNKf7/YDMlwZwv9hTnts X-Received: by 2002:a6b:6810:0:b0:7be:e376:fc44 with SMTP id d16-20020a6b6810000000b007bee376fc44mr15847942ioc.2.1705527148247; Wed, 17 Jan 2024 13:32:28 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1705527148; cv=none; d=google.com; s=arc-20160816; b=PWdoLsPUvVVC8TDv/6jAEbZ5tf+lYvwcNhIO8bXjzi2Iv7I697ypmlBJA2xl9YDh5B WdlOpUV6cwguzYTsUC8zGx2XO3omPDnTw3uAmMz1AShUNXDqfLcG77pcz3lNTMPtvIVX TlZWpS0lo7DuG9L7WXArHSKF/yHdq16wyx6NBBVYcdsRkM3bhYDhWxmOnxYOuwIeCiZj 9uV9KyRF6UgBgx9nl3gEJ//Lzx+LuMAat55nHRz+21XpLDOW6pbPvKOlvDZt7ZewF4TL a4D7FlBgSZMz9crHkg4Nl1dS2AK6WvneaW4C15BJ32FredgkCr+Yw5RXh1WB47zNEFkY dftQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=errors-to:content-transfer-encoding:list-subscribe:list-help :list-post:list-archive:list-unsubscribe:list-id:precedence:subject :mime-version:references:in-reply-to:message-id:date:to:from :dkim-signature:dkim-signature; bh=aodwKsFV6/DVTmHVtXSS94WIbDaB3VNRNdABR+bzvR8=; fh=4NbAC/LsuMLI0S0hprUlLSLCiHwg6SCAifhH718Jh0Q=; b=fedqEhA+LhLU8IJg8sBp9TLoGS9ntDHwyTbeOzzQaZfYyD2OIwPl7N5zy42BBIROqY O0foHi3UPzNpORNc3HQ+15FlL5jGMpIHnr+e2b3qmkU14VrDjDLpmfJyy5L3nAQC6/8A c04aAo6Wb5CvME8l9PTglckAUYEqkRpi1dl0NNY0yHud3nxsDMJKvT1Opgj2sxp3aF4q seXj/j0/+JO7HYvrG9qQCOMwJPCXHk9xOcJ+7VB1pe3IQkte5ig5IbcG+JY3VJBTnJD8 XaV97Ksd2d9wsEDsYLIHzA5ScBRoGgi5U/fYG5CsfAnPousx+J78KniMBDAvuS8mAQGM SUwg== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=WExUthmk; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=YrJdm1Cz; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=muc.de Received: from lists.sourceforge.net (lists.sourceforge.net. [216.105.38.7]) by mx.google.com with ESMTPS id k66-20020a633d45000000b005ce6b79b55dsi243833pga.165.2024.01.17.13.32.28 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 17 Jan 2024 13:32:28 -0800 (PST) Received-SPF: pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) client-ip=216.105.38.7; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=WExUthmk; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=YrJdm1Cz; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=muc.de Received: from [127.0.0.1] (helo=sfs-ml-4.v29.lw.sourceforge.com) by sfs-ml-4.v29.lw.sourceforge.com with esmtp (Exim 4.95) (envelope-from ) id 1rQDW0-0004Q3-I8; Wed, 17 Jan 2024 21:32:04 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-4.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1rQDVx-0004Pp-Ng for openvpn-devel@lists.sourceforge.net; Wed, 17 Jan 2024 21:32:02 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-ID:Date:Subject:To:From:Sender:Reply-To:Cc:Content-Type: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=kIe9tR40Du3ndsgR54LbnhjV6tTQKRNqMC9igE4/kMM=; b=WExUthmkVmOI2puZ6gVdYV5HC/ /K/nPeAeWh4TjEW0oZW6ZErtLOrYIxQ6eA9pNj0dHjgP7v/8/mJmc9Tt057huRDVXCUDoTc5tKhRX A89GAAP8vtKgk1u4Z4IuEHXDO+6rA5C9vO1nBwUkSNUlCptxO9U6/VXZkehNVsiTjIJw=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID: Date:Subject:To:From:Sender:Reply-To:Cc:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=kIe9tR40Du3ndsgR54LbnhjV6tTQKRNqMC9igE4/kMM=; b=YrJdm1CzPX2X6YrHvPdBeoyHGC nHuJe4rUY40Wb7g5epYRGGEziyHR7SWKmaNylCAwTZXDdqZFyCQAeIe04elwNT2Solul8vnky5vAP oEStBETUihtPBELuKxxAYZMZ5AHUOIC98SdWOPE0WuGUjur0IU5zJcCPXW4DC3/9uhbA=; Received: from dhcp-174.greenie.muc.de ([193.149.48.174] helo=blue.greenie.muc.de) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.95) id 1rQDVs-00007D-Ov for openvpn-devel@lists.sourceforge.net; Wed, 17 Jan 2024 21:32:01 +0000 Received: from blue.greenie.muc.de (localhost [127.0.0.1]) by blue.greenie.muc.de (8.17.1.9/8.17.1.9) with ESMTP id 40HLVj6Y017422 for ; Wed, 17 Jan 2024 22:31:45 +0100 Received: (from gert@localhost) by blue.greenie.muc.de (8.17.1.9/8.17.1.9/Submit) id 40HLVjhb017421 for openvpn-devel@lists.sourceforge.net; Wed, 17 Jan 2024 22:31:45 +0100 From: Gert Doering To: openvpn-devel@lists.sourceforge.net Date: Wed, 17 Jan 2024 22:31:44 +0100 Message-ID: <20240117213144.17412-1-gert@greenie.muc.de> X-Mailer: git-send-email 2.43.0 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Score: -0.0 (/) X-Spam-Report: Spam detection software, running on the system "util-spamd-2.v13.lw.sourceforge.com", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: From: Frank Lichtenheld UTs for basic functionality, without management functions. v2: - add CMake support - add GHA support for both MSVC and mingw v3: - fix distcheck by adding input/ directory to dist Content analysis details: (-0.0 points, 6.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.0 SPF_PASS SPF: sender matches SPF record -0.0 T_SCC_BODY_TEXT_LINE No description available. X-Headers-End: 1rQDVs-00007D-Ov Subject: [Openvpn-devel] [PATCH v7] test_user_pass: new UT for get_user_pass X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox X-GMAIL-THRID: =?utf-8?q?1788374834909909222?= X-GMAIL-MSGID: =?utf-8?q?1788374834909909222?= From: Frank Lichtenheld UTs for basic functionality, without management functions. v2: - add CMake support - add GHA support for both MSVC and mingw v3: - fix distcheck by adding input/ directory to dist Change-Id: I193aef06912f01426dd4ac298aadfab97dd75a35 Signed-off-by: Frank Lichtenheld Acked-by: Arne Schwabe --- This change was reviewed on Gerrit and approved by at least one developer. I request to merge it to master. Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/468 This mail reflects revision 7 of this Change. Acked-by according to Gerrit (reflected above): Arne Schwabe diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 51100c3..cbe77bc 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -85,11 +85,13 @@ fail-fast: false matrix: arch: [x86, x64] - test: [argv, auth_token, buffer, cryptoapi, crypto, misc, ncp, packet_id, pkt, provider, tls_crypt] + test: [argv, auth_token, buffer, cryptoapi, crypto, misc, ncp, packet_id, pkt, provider, tls_crypt, user_pass] runs-on: windows-latest name: "mingw unittest ${{ matrix.test }} - ${{ matrix.arch }} - OSSL" steps: + - name: Checkout OpenVPN + uses: actions/checkout@v3 - name: Retrieve mingw unittest uses: actions/download-artifact@v3 with: @@ -97,6 +99,8 @@ path: unittests - name: Run ${{ matrix.test }} unit test run: ./unittests/test_${{ matrix.test }}.exe + env: + srcdir: "${{ github.workspace }}/tests/unit_tests/openvpn" ubuntu: strategy: @@ -279,6 +283,7 @@ configurePreset: win-${{ matrix.arch }}-release buildPreset: win-${{ matrix.arch }}-release testPreset: win-${{ matrix.arch }}-release + testPresetAdditionalArgs: "['--output-on-failure']" - uses: actions/upload-artifact@v3 with: diff --git a/CMakeLists.txt b/CMakeLists.txt index bc46c27..bc2bb31 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -592,6 +592,7 @@ "test_packet_id" "test_pkt" "test_provider" + "test_user_pass" ) if (WIN32) @@ -650,6 +651,10 @@ # test_networking needs special environment if (NOT ${test_name} STREQUAL "test_networking") add_test(${test_name} ${test_name}) + # for compat with autotools make check + set(_UT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/tests/unit_tests/openvpn) + set_tests_properties(${test_name} PROPERTIES + ENVIRONMENT "srcdir=${_UT_SOURCE_DIR}") endif () add_executable(${test_name} tests/unit_tests/openvpn/${test_name}.c @@ -744,6 +749,15 @@ src/openvpn/base64.c ) + target_sources(test_user_pass PRIVATE + tests/unit_tests/openvpn/mock_get_random.c + tests/unit_tests/openvpn/mock_win32_execve.c + src/openvpn/base64.c + src/openvpn/console.c + src/openvpn/env_set.c + src/openvpn/run_command.c + ) + if (TARGET test_argv) target_link_options(test_argv PRIVATE -Wl,--wrap=parse_line) target_sources(test_argv PRIVATE diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h index d51609d..5ae61b5 100644 --- a/src/openvpn/misc.h +++ b/src/openvpn/misc.h @@ -118,12 +118,31 @@ #define GET_USER_PASS_INLINE_CREDS (1<<10) /* indicates that auth_file is actually inline creds */ +/** + * Retrieves the user credentials from various sources depending on the flags. + * + * @param up The user_pass structure to store the retrieved credentials. + * @param auth_file The path to the authentication file. Might be NULL. + * @param prefix The prefix to prepend to user prompts. + * @param flags Additional flags to control the behavior of the function. + * @param auth_challenge The authentication challenge string. + * @return true if the user credentials were successfully retrieved, false otherwise. + */ bool get_user_pass_cr(struct user_pass *up, const char *auth_file, const char *prefix, const unsigned int flags, const char *auth_challenge); +/** + * Retrieves the user credentials from various sources depending on the flags. + * + * @param up The user_pass structure to store the retrieved credentials. + * @param auth_file The path to the authentication file. Might be NULL. + * @param prefix The prefix to prepend to user prompts. + * @param flags Additional flags to control the behavior of the function. + * @return true if the user credentials were successfully retrieved, false otherwise. + */ static inline bool get_user_pass(struct user_pass *up, const char *auth_file, diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h index a021c91..d2859fe 100644 --- a/src/openvpn/syshead.h +++ b/src/openvpn/syshead.h @@ -524,4 +524,10 @@ #define ENABLE_MEMSTATS #endif +#ifdef _MSC_VER +#ifndef PATH_MAX +#define PATH_MAX MAX_PATH +#endif +#endif + #endif /* ifndef SYSHEAD_H */ diff --git a/tests/unit_tests/openvpn/Makefile.am b/tests/unit_tests/openvpn/Makefile.am index cecf4dc..342f428 100644 --- a/tests/unit_tests/openvpn/Makefile.am +++ b/tests/unit_tests/openvpn/Makefile.am @@ -1,5 +1,7 @@ AUTOMAKE_OPTIONS = foreign +EXTRA_DIST = input + AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING) Unit-Tests' test_binaries= @@ -9,7 +11,7 @@ endif test_binaries += crypto_testdriver packet_id_testdriver auth_token_testdriver ncp_testdriver misc_testdriver \ - pkt_testdriver + pkt_testdriver user_pass_testdriver if HAVE_LD_WRAP_SUPPORT if !WIN32 test_binaries += tls_crypt_testdriver @@ -216,6 +218,22 @@ $(top_srcdir)/src/openvpn/base64.c +user_pass_testdriver_CFLAGS = @TEST_CFLAGS@ \ + -I$(top_srcdir)/include -I$(top_srcdir)/src/compat -I$(top_srcdir)/src/openvpn +user_pass_testdriver_LDFLAGS = @TEST_LDFLAGS@ + +user_pass_testdriver_SOURCES = test_user_pass.c mock_msg.c \ + $(top_srcdir)/src/openvpn/buffer.c \ + $(top_srcdir)/src/openvpn/console.c \ + $(top_srcdir)/src/openvpn/env_set.c \ + mock_win32_execve.c \ + $(top_srcdir)/src/openvpn/run_command.c \ + mock_get_random.c \ + $(top_srcdir)/src/openvpn/platform.c \ + $(top_srcdir)/src/openvpn/win32-util.c \ + $(top_srcdir)/src/openvpn/base64.c + + ncp_testdriver_CFLAGS = @TEST_CFLAGS@ \ -I$(top_srcdir)/include -I$(top_srcdir)/src/compat -I$(top_srcdir)/src/openvpn \ $(OPTIONAL_CRYPTO_CFLAGS) diff --git a/tests/unit_tests/openvpn/input/user_only.txt b/tests/unit_tests/openvpn/input/user_only.txt new file mode 100644 index 0000000..3ca0db3 --- /dev/null +++ b/tests/unit_tests/openvpn/input/user_only.txt @@ -0,0 +1 @@ +fuser diff --git a/tests/unit_tests/openvpn/input/user_pass.txt b/tests/unit_tests/openvpn/input/user_pass.txt new file mode 100644 index 0000000..31b38ef --- /dev/null +++ b/tests/unit_tests/openvpn/input/user_pass.txt @@ -0,0 +1,2 @@ +fuser +fpassword diff --git a/tests/unit_tests/openvpn/test_user_pass.c b/tests/unit_tests/openvpn/test_user_pass.c new file mode 100644 index 0000000..ab4dfe4 --- /dev/null +++ b/tests/unit_tests/openvpn/test_user_pass.c @@ -0,0 +1,260 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2023 OpenVPN Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#undef ENABLE_SYSTEMD + +#include "syshead.h" +#include "manage.h" + +#include +#include +#include +#include + +#include "misc.c" + +struct management *management; /* global */ + +/* mocking */ +bool +query_user_exec_builtin(void) +{ + /* Loop through configured query_user slots */ + for (int i = 0; i < QUERY_USER_NUMSLOTS && query_user[i].response != NULL; i++) + { + check_expected(query_user[i].prompt); + strncpy(query_user[i].response, mock_ptr_type(char *), query_user[i].response_len); + } + + return mock(); +} +void +management_auth_failure(struct management *man, const char *type, const char *reason) +{ + assert_true(0); +} +bool +management_query_user_pass(struct management *man, + struct user_pass *up, + const char *type, + const unsigned int flags, + const char *static_challenge) +{ + assert_true(0); + return false; +} +/* stubs for some unused functions instead of pulling in too many dependencies */ +int +parse_line(const char *line, char **p, const int n, const char *file, + const int line_num, int msglevel, struct gc_arena *gc) +{ + assert_true(0); + return 0; +} + +/* tooling */ +static void +reset_user_pass(struct user_pass *up) +{ + up->defined = false; + up->token_defined = false; + up->nocache = false; + strcpy(up->username, "user"); + strcpy(up->password, "password"); +} + +static void +test_get_user_pass_defined(void **state) +{ + struct user_pass up = { 0 }; + reset_user_pass(&up); + up.defined = true; + assert_true(get_user_pass_cr(&up, NULL, "UT", 0, NULL)); +} + +static void +test_get_user_pass_needok(void **state) +{ + struct user_pass up = { 0 }; + reset_user_pass(&up); + unsigned int flags = GET_USER_PASS_NEED_OK; + + expect_string(query_user_exec_builtin, query_user[i].prompt, "NEED-OK|UT|user:"); + will_return(query_user_exec_builtin, ""); + will_return(query_user_exec_builtin, true); + /*FIXME: query_user_exec() called even though nothing queued */ + will_return(query_user_exec_builtin, true); + assert_true(get_user_pass_cr(&up, NULL, "UT", flags, NULL)); + assert_true(up.defined); + assert_string_equal(up.password, "ok"); + + reset_user_pass(&up); + + expect_string(query_user_exec_builtin, query_user[i].prompt, "NEED-OK|UT|user:"); + will_return(query_user_exec_builtin, "cancel"); + will_return(query_user_exec_builtin, true); + /*FIXME: query_user_exec() called even though nothing queued */ + will_return(query_user_exec_builtin, true); + assert_true(get_user_pass_cr(&up, NULL, "UT", flags, NULL)); + assert_true(up.defined); + assert_string_equal(up.password, "cancel"); +} + +static void +test_get_user_pass_inline_creds(void **state) +{ + struct user_pass up = { 0 }; + reset_user_pass(&up); + unsigned int flags = GET_USER_PASS_INLINE_CREDS; + + /*FIXME: query_user_exec() called even though nothing queued */ + will_return(query_user_exec_builtin, true); + assert_true(get_user_pass_cr(&up, "iuser\nipassword", "UT", flags, NULL)); + assert_true(up.defined); + assert_string_equal(up.username, "iuser"); + assert_string_equal(up.password, "ipassword"); + + reset_user_pass(&up); + + expect_string(query_user_exec_builtin, query_user[i].prompt, "Enter UT Password:"); + will_return(query_user_exec_builtin, "cpassword"); + will_return(query_user_exec_builtin, true); + /* will try to retrieve missing password from stdin */ + assert_true(get_user_pass_cr(&up, "iuser", "UT", flags, NULL)); + assert_true(up.defined); + assert_string_equal(up.username, "iuser"); + assert_string_equal(up.password, "cpassword"); + + reset_user_pass(&up); + + flags |= GET_USER_PASS_PASSWORD_ONLY; + /*FIXME: query_user_exec() called even though nothing queued */ + will_return(query_user_exec_builtin, true); + assert_true(get_user_pass_cr(&up, "ipassword\n", "UT", flags, NULL)); + assert_true(up.defined); + assert_string_equal(up.username, "user"); + assert_string_equal(up.password, "ipassword"); + + reset_user_pass(&up); + + flags |= GET_USER_PASS_PASSWORD_ONLY; + expect_string(query_user_exec_builtin, query_user[i].prompt, "Enter UT Password:"); + will_return(query_user_exec_builtin, "cpassword"); + will_return(query_user_exec_builtin, true); + /* will try to retrieve missing password from stdin */ + assert_true(get_user_pass_cr(&up, "", "UT", flags, NULL)); + assert_true(up.defined); + assert_string_equal(up.username, "user"); + assert_string_equal(up.password, "cpassword"); +} + +static void +test_get_user_pass_authfile_stdin(void **state) +{ + struct user_pass up = { 0 }; + reset_user_pass(&up); + unsigned int flags = 0; + + expect_string(query_user_exec_builtin, query_user[i].prompt, "Enter UT Username:"); + expect_string(query_user_exec_builtin, query_user[i].prompt, "Enter UT Password:"); + will_return(query_user_exec_builtin, "cuser"); + will_return(query_user_exec_builtin, "cpassword"); + will_return(query_user_exec_builtin, true); + assert_true(get_user_pass_cr(&up, "stdin", "UT", flags, NULL)); + assert_true(up.defined); + assert_string_equal(up.username, "cuser"); + assert_string_equal(up.password, "cpassword"); + + reset_user_pass(&up); + + flags |= GET_USER_PASS_PASSWORD_ONLY; + expect_string(query_user_exec_builtin, query_user[i].prompt, "Enter UT Password:"); + will_return(query_user_exec_builtin, "cpassword"); + will_return(query_user_exec_builtin, true); + assert_true(get_user_pass_cr(&up, "stdin", "UT", flags, NULL)); + assert_true(up.defined); + assert_string_equal(up.username, "user"); + assert_string_equal(up.password, "cpassword"); +} + +static void +test_get_user_pass_authfile_file(void **state) +{ + struct user_pass up = { 0 }; + reset_user_pass(&up); + unsigned int flags = 0; + + const char *srcdir = getenv("srcdir"); + assert_non_null(srcdir); + char authfile[PATH_MAX] = { 0 }; + + snprintf(authfile, PATH_MAX, "%s/%s", srcdir, "input/user_pass.txt"); + /*FIXME: query_user_exec() called even though nothing queued */ + will_return(query_user_exec_builtin, true); + assert_true(get_user_pass_cr(&up, authfile, "UT", flags, NULL)); + assert_true(up.defined); + assert_string_equal(up.username, "fuser"); + assert_string_equal(up.password, "fpassword"); + + reset_user_pass(&up); + + snprintf(authfile, PATH_MAX, "%s/%s", srcdir, "input/user_only.txt"); + expect_string(query_user_exec_builtin, query_user[i].prompt, "Enter UT Password:"); + will_return(query_user_exec_builtin, "cpassword"); + will_return(query_user_exec_builtin, true); + /* will try to retrieve missing password from stdin */ + assert_true(get_user_pass_cr(&up, authfile, "UT", flags, NULL)); + assert_true(up.defined); + assert_string_equal(up.username, "fuser"); + assert_string_equal(up.password, "cpassword"); + + reset_user_pass(&up); + + flags |= GET_USER_PASS_PASSWORD_ONLY; + snprintf(authfile, PATH_MAX, "%s/%s", srcdir, "input/user_only.txt"); + /*FIXME: query_user_exec() called even though nothing queued */ + will_return(query_user_exec_builtin, true); + assert_true(get_user_pass_cr(&up, authfile, "UT", flags, NULL)); + assert_true(up.defined); + assert_string_equal(up.username, "user"); + assert_string_equal(up.password, "fuser"); +} + +const struct CMUnitTest user_pass_tests[] = { + cmocka_unit_test(test_get_user_pass_defined), + cmocka_unit_test(test_get_user_pass_needok), + cmocka_unit_test(test_get_user_pass_inline_creds), + cmocka_unit_test(test_get_user_pass_authfile_stdin), + cmocka_unit_test(test_get_user_pass_authfile_file), +}; + +int +main(void) +{ + return cmocka_run_group_tests(user_pass_tests, NULL, NULL); +}