summaryrefslogtreecommitdiffstats
path: root/src/VBox/Frontends/Common/PasswordInput.cpp
blob: db791ada3c4ec0149cf1ea43635c840f2f8c1eb6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/* $Id: PasswordInput.cpp $ */
/** @file
 * Frontend shared bits - Password file and console input helpers.
 */

/*
 * Copyright (C) 2012-2023 Oracle and/or its affiliates.
 *
 * This file is part of VirtualBox base platform packages, as
 * available from https://www.virtualbox.org.
 *
 * 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, in version 3 of the
 * License.
 *
 * 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, see <https://www.gnu.org/licenses>.
 *
 * SPDX-License-Identifier: GPL-3.0-only
 */


/*********************************************************************************************************************************
*   Header Files                                                                                                                 *
*********************************************************************************************************************************/
#include "PasswordInput.h"

#include <iprt/ctype.h>
#include <iprt/errcore.h>
#include <iprt/message.h>
#include <iprt/stream.h>

#include <VBox/com/errorprint.h>


/**
 * Reads a password from the password file.
 *
 * Only first line is used. The passwords length must be less than 512 bytes
 *
 * @param   pszFilename  The path to file containing the password
 * @param   pPasswd      The string where password will be returned
 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg.
 */
RTEXITCODE readPasswordFile(const char *pszFilename, com::Utf8Str *pPasswd)
{
    size_t cbFile;
    char szPasswd[512] = { 0 };
    int vrc = VINF_SUCCESS;
    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
    bool fStdIn = !strcmp(pszFilename, "stdin");
    PRTSTREAM pStrm;
    if (!fStdIn)
        vrc = RTStrmOpen(pszFilename, "r", &pStrm);
    else
        pStrm = g_pStdIn;
    if (RT_SUCCESS(vrc))
    {
        vrc = RTStrmReadEx(pStrm, szPasswd, sizeof(szPasswd)-1, &cbFile);
        if (RT_SUCCESS(vrc))
        {
            size_t cbSize = RT_MIN(sizeof(szPasswd)-1, cbFile);
            unsigned i;
            for (i = 0; i < cbSize && !RTLocCIsCntrl(szPasswd[i]); i++)
                ;
            szPasswd[i] = '\0';
            /* If the line containing password doesn't fit into buffer */
            if (i >= sizeof(szPasswd)-1 && cbFile >= sizeof(szPasswd))
                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Provided password in file '%s' is too long", pszFilename);
            else
                *pPasswd = szPasswd;
        }
        else
            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Cannot read password from file '%s': %Rrc", pszFilename, vrc);
        if (!fStdIn)
            RTStrmClose(pStrm);
    }
    else
        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Cannot open password file '%s' (%Rrc)", pszFilename, vrc);

    return rcExit;
}


/**
 * Sets password for settings from password file
 *
 * Only first line is used. The passwords length must be less than 512 bytes
 *
 * @param virtualBox   The IVirtualBox interface the settings password will be set for
 * @param pszFilename  The path to file containing the password
 * @return RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg.
 */
RTEXITCODE settingsPasswordFile(ComPtr<IVirtualBox> virtualBox, const char *pszFilename)
{
    com::Utf8Str passwd;
    RTEXITCODE rcExit = readPasswordFile(pszFilename, &passwd);
    if (rcExit == RTEXITCODE_SUCCESS)
    {
        HRESULT hrc;
        CHECK_ERROR(virtualBox, SetSettingsSecret(com::Bstr(passwd).raw()));
        if (FAILED(hrc))
            rcExit = RTEXITCODE_FAILURE;
    }

    return rcExit;
}


/**
 * Gets the password from the user input
 * *
 * @param pPassword  The string where password will be returned
 * @param pszPrompt  The prompt string for user
 * @return RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg.
 */
RTEXITCODE readPasswordFromConsole(com::Utf8Str *pPassword, const char *pszPrompt, ...)
{
    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
    char aszPwdInput[_1K] = { 0 };
    va_list vaArgs;

    va_start(vaArgs, pszPrompt);
    int vrc = RTStrmPrintfV(g_pStdOut, pszPrompt, vaArgs);
    if (RT_SUCCESS(vrc))
    {
        bool fEchoOld = false;
        vrc = RTStrmInputGetEchoChars(g_pStdIn, &fEchoOld);
        if (RT_SUCCESS(vrc))
        {
            vrc = RTStrmInputSetEchoChars(g_pStdIn, false);
            if (RT_SUCCESS(vrc))
            {
                vrc = RTStrmGetLine(g_pStdIn, &aszPwdInput[0], sizeof(aszPwdInput));
                if (RT_SUCCESS(vrc))
                {
#ifdef RT_OS_WINDOWS
                    /*
                     * Returned string encoded in console code page (e.g. Win-125X or CP-XXX).
                     * Convert it to Utf-8
                     */
                    char *pszPassword = NULL;
                    vrc = RTStrConsoleCPToUtf8(&pszPassword, aszPwdInput);
                    if (RT_SUCCESS(vrc) && pszPassword)
                    {
                        *pPassword = pszPassword;
                        RTMemFree(pszPassword);
                    }
                    else
                        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE,
                                                "Failed to convert password from windows console codepage to Utf-8 (%Rrc)",
                                                vrc);
#else
                    *pPassword = aszPwdInput;
#endif
                }
                else
                    rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed read password from command line (%Rrc)", vrc);

                int vrc2 = RTStrmInputSetEchoChars(g_pStdIn, fEchoOld);
                AssertRC(vrc2);
            }
            else
                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to disable echoing typed characters (%Rrc)", vrc);
        }
        else
            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to retrieve echo setting (%Rrc)", vrc);

        RTStrmPutStr(g_pStdOut, "\n");
    }
    else
        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to print prompt (%Rrc)", vrc);
    va_end(vaArgs);

    return rcExit;
}