Commit 259434b8 authored by Marc-André Lureau's avatar Marc-André Lureau Committed by Michael Roth
Browse files

qemu-ga: implement win32 guest-set-user-password



Use NetUserSetInfo() to set the user password.

This function is notoriously known to be problematic for users with EFS
encrypted files. But the alternative, NetUserChangePassword() requires
the old password. Nevertheless, The EFS file should be recovered by
changing back to the old password.

Signed-off-by: default avatarMarc-André Lureau <marcandre.lureau@gmail.com>
Reviewed-by: default avatarDaniel P. Berrange <berrange@redhat.com>
Signed-off-by: default avatarMichael Roth <mdroth@linux.vnet.ibm.com>
parent 665b5d0d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -732,7 +732,7 @@ if test "$mingw32" = "yes" ; then
  sysconfdir="\${prefix}"
  local_statedir=
  confsuffix=""
  libs_qga="-lws2_32 -lwinmm -lpowrprof -liphlpapi $libs_qga"
  libs_qga="-lws2_32 -lwinmm -lpowrprof -liphlpapi -lnetapi32 $libs_qga"
fi

werror=""
+75 −2
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@
#include <setupapi.h>
#include <initguid.h>
#endif
#include <lm.h>

#include "qga/guest-agent-core.h"
#include "qga/vss-win32.h"
#include "qga-qmp-commands.h"
@@ -1192,12 +1194,84 @@ int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
    return -1;
}

static gchar *
get_net_error_message(gint error)
{
    HMODULE module = NULL;
    gchar *retval = NULL;
    wchar_t *msg = NULL;
    int flags, nchars;

    flags = FORMAT_MESSAGE_ALLOCATE_BUFFER
        |FORMAT_MESSAGE_IGNORE_INSERTS
        |FORMAT_MESSAGE_FROM_SYSTEM;

    if (error >= NERR_BASE && error <= MAX_NERR) {
        module = LoadLibraryExW(L"netmsg.dll", NULL, LOAD_LIBRARY_AS_DATAFILE);

        if (module != NULL) {
            flags |= FORMAT_MESSAGE_FROM_HMODULE;
        }
    }

    FormatMessageW(flags, module, error, 0, (LPWSTR)&msg, 0, NULL);

    if (msg != NULL) {
        nchars = wcslen(msg);

        if (nchars > 2 && msg[nchars-1] == '\n' && msg[nchars-2] == '\r') {
            msg[nchars-2] = '\0';
        }

        retval = g_utf16_to_utf8(msg, -1, NULL, NULL, NULL);

        LocalFree(msg);
    }

    if (module != NULL) {
        FreeLibrary(module);
    }

    return retval;
}

void qmp_guest_set_user_password(const char *username,
                                 const char *password,
                                 bool crypted,
                                 Error **errp)
{
    NET_API_STATUS nas;
    char *rawpasswddata = NULL;
    size_t rawpasswdlen;
    wchar_t *user, *wpass;
    USER_INFO_1003 pi1003 = { 0, };

    if (crypted) {
        error_setg(errp, QERR_UNSUPPORTED);
        return;
    }

    rawpasswddata = (char *)g_base64_decode(password, &rawpasswdlen);
    rawpasswddata = g_renew(char, rawpasswddata, rawpasswdlen + 1);
    rawpasswddata[rawpasswdlen] = '\0';

    user = g_utf8_to_utf16(username, -1, NULL, NULL, NULL);
    wpass = g_utf8_to_utf16(rawpasswddata, -1, NULL, NULL, NULL);

    pi1003.usri1003_password = wpass;
    nas = NetUserSetInfo(NULL, user,
                         1003, (LPBYTE)&pi1003,
                         NULL);

    if (nas != NERR_Success) {
        gchar *msg = get_net_error_message(nas);
        error_setg(errp, "failed to set password: %s", msg);
        g_free(msg);
    }

    g_free(user);
    g_free(wpass);
    g_free(rawpasswddata);
}

GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp)
@@ -1225,7 +1299,6 @@ GList *ga_command_blacklist_init(GList *blacklist)
    const char *list_unsupported[] = {
        "guest-suspend-hybrid",
        "guest-get-vcpus", "guest-set-vcpus",
        "guest-set-user-password",
        "guest-get-memory-blocks", "guest-set-memory-blocks",
        "guest-get-memory-block-size",
        "guest-fsfreeze-freeze-list",