From patchwork Sat Jan 27 20:07:16 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gert Doering X-Patchwork-Id: 3595 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7001:10:b0:550:f63e:f504 with SMTP id rm16csp644769mab; Sat, 27 Jan 2024 12:08:08 -0800 (PST) X-Google-Smtp-Source: AGHT+IEqEC3HAx9lWBscSnQFSCKemUBp14kaQkP0oI0L8/N8VplMEkmNgV14bIplZeuv/YHwPR5w X-Received: by 2002:a05:6a20:da87:b0:19c:a1b4:e52e with SMTP id iy7-20020a056a20da8700b0019ca1b4e52emr1648336pzb.0.1706386088227; Sat, 27 Jan 2024 12:08:08 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1706386088; cv=none; d=google.com; s=arc-20160816; b=F7/BYx/1oRu4klnHAiHrNvMVDTZfvENP2qozaLhmtiBC1RyN+2tUEyoa8bCI9DHmy0 DxU/cdevYpuDxtqKcZORxf3FVBtypbU7wPsS8CJOYy9sgIETacKYOT80YREfSmMfsq51 P9Z84XNjNGE5OqAQXUS9ralHuoKikZ4l2pXEEWsw0i9BnF+0RCv+7PoLp7j1KiFN0SB3 hKkP6dMAy3chCOVq7l3zCgT0Bv//gfTNVuFsqYKg1roCPnx5jo5YBdPKLnV5cKtARR/8 pdr+At4ou22D5YvR6dVy5WSTfQfHdvWoMm2NaAmkXcpo+BvAv7bUK4XX3/+K6DEccw76 nGdg== 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=MWq98983PI9pDYVXyL5v0uRnGpFsVFmqkSSQLfM35Oo=; fh=4NbAC/LsuMLI0S0hprUlLSLCiHwg6SCAifhH718Jh0Q=; b=uV+I8k/PWgTJhkQMohUVvzTdiK7PcKB4yysorVL2Jc7ojEklqDtN1eZHzXav5LKF82 WMXGAKGD5jCfDjgaA2mfhGGOW1zeSQ04wYOOXo56I2fgEFSBj9M04jivzkIRvweLflnq 1oqikxS+nE+ZNZV1SfBkNEEmf89Uibhlb8nZY1JBOfVYCvqviaqipaHb9qk8/GzUNApQ vPykxXJaDCCJpqwb82mdIPLHaUZ6RqOrcIPuYq+n/EC/1ousxxBGJqKNUXpzF4RoqTxu pRB0oI6ei0nLa7pokazhdiF5gxkML88f8dU1W26MEWZ7hCwoqoh2aJD3fxDcEILIHbgu Iz9A== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=c+2O09i6; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=G6VzkPKG; 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 du2-20020a056a002b4200b006d9b04b4825si3265618pfb.15.2024.01.27.12.08.07 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sat, 27 Jan 2024 12:08:08 -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=c+2O09i6; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=G6VzkPKG; 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 1rToxi-0007Gq-45; Sat, 27 Jan 2024 20:07:34 +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 1rToxg-0007Gk-Om for openvpn-devel@lists.sourceforge.net; Sat, 27 Jan 2024 20:07:32 +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=iHM+UppKMWdcozp1LzMhOt8tDph0hPOQLINqFLZL7C8=; b=c+2O09i6ZXTUDEYeRrQeTeNaM9 RtANopP8N2JSsDTcQKuUM3LGzcgZS8ow0iL/GmgMYlxoAIKaxahzewZDmNCLoeNjSkunD+xQmFbux 96ExdkFKQOJnTlTCxWhpr+jgQIhoDCTH/nohqGDZFfW0yBl7oIAiyBLWLDLHV5pT6/rw=; 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=iHM+UppKMWdcozp1LzMhOt8tDph0hPOQLINqFLZL7C8=; b=G6VzkPKG/kZFb78J1u1vndZCHC PojpA/UsfojjkI3LPckLzT4kNX6n1w6pkQcp3g/rg1pFHGL6nTa4n7bPjkSiH3woXltEfo0+HdT6L /tU1NdQHdDYF+7hQLsM59ON3LePPYm2PknW/Qc1Iy9J+8DeqAQFw1MEC/TXSdVnI4Dho=; 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 1rToxd-0006Qk-GS for openvpn-devel@lists.sourceforge.net; Sat, 27 Jan 2024 20:07:32 +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 40RK7Iq3010302 for ; Sat, 27 Jan 2024 21:07:18 +0100 Received: (from gert@localhost) by blue.greenie.muc.de (8.17.1.9/8.17.1.9/Submit) id 40RK7HqJ010301 for openvpn-devel@lists.sourceforge.net; Sat, 27 Jan 2024 21:07:17 +0100 From: Gert Doering To: openvpn-devel@lists.sourceforge.net Date: Sat, 27 Jan 2024 21:07:16 +0100 Message-ID: <20240127200716.10255-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-1.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: 1rToxd-0006Qk-GS Subject: [Openvpn-devel] [PATCH v8] 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?1789275499067279962?= 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 8 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 cc98813..bc937e5 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, ssl, tls_crypt] + test: [argv, auth_token, buffer, cryptoapi, crypto, misc, ncp, packet_id, pkt, provider, ssl, 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 5e07d50..be55c60 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -604,6 +604,7 @@ "test_pkt" "test_provider" "test_ssl" + "test_user_pass" ) if (WIN32) @@ -662,6 +663,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 @@ -782,6 +787,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 f81a10f..88a694d 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 ssl_testdriver + pkt_testdriver ssl_testdriver user_pass_testdriver if HAVE_LD_WRAP_SUPPORT if !WIN32 @@ -251,6 +253,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); +}