qemu/qga/commands-win32.c
<<
>>
Prefs
   1/*
   2 * QEMU Guest Agent win32-specific command implementations
   3 *
   4 * Copyright IBM Corp. 2012
   5 *
   6 * Authors:
   7 *  Michael Roth      <mdroth@linux.vnet.ibm.com>
   8 *  Gal Hammer        <ghammer@redhat.com>
   9 *
  10 * This work is licensed under the terms of the GNU GPL, version 2 or later.
  11 * See the COPYING file in the top-level directory.
  12 */
  13
  14#ifndef _WIN32_WINNT
  15#   define _WIN32_WINNT 0x0600
  16#endif
  17
  18#include "qemu/osdep.h"
  19#include <wtypes.h>
  20#include <powrprof.h>
  21#include <winsock2.h>
  22#include <ws2tcpip.h>
  23#include <iptypes.h>
  24#include <iphlpapi.h>
  25#ifdef CONFIG_QGA_NTDDSCSI
  26#include <winioctl.h>
  27#include <ntddscsi.h>
  28#include <setupapi.h>
  29#include <initguid.h>
  30#endif
  31#include <lm.h>
  32#include <wtsapi32.h>
  33#include <wininet.h>
  34
  35#include "guest-agent-core.h"
  36#include "vss-win32.h"
  37#include "qga-qapi-commands.h"
  38#include "qapi/error.h"
  39#include "qapi/qmp/qerror.h"
  40#include "qemu/queue.h"
  41#include "qemu/host-utils.h"
  42#include "qemu/base64.h"
  43
  44#ifndef SHTDN_REASON_FLAG_PLANNED
  45#define SHTDN_REASON_FLAG_PLANNED 0x80000000
  46#endif
  47
  48/* multiple of 100 nanoseconds elapsed between windows baseline
  49 *    (1/1/1601) and Unix Epoch (1/1/1970), accounting for leap years */
  50#define W32_FT_OFFSET (10000000ULL * 60 * 60 * 24 * \
  51                       (365 * (1970 - 1601) +       \
  52                        (1970 - 1601) / 4 - 3))
  53
  54#define INVALID_SET_FILE_POINTER ((DWORD)-1)
  55
  56typedef struct GuestFileHandle {
  57    int64_t id;
  58    HANDLE fh;
  59    QTAILQ_ENTRY(GuestFileHandle) next;
  60} GuestFileHandle;
  61
  62static struct {
  63    QTAILQ_HEAD(, GuestFileHandle) filehandles;
  64} guest_file_state = {
  65    .filehandles = QTAILQ_HEAD_INITIALIZER(guest_file_state.filehandles),
  66};
  67
  68#define FILE_GENERIC_APPEND (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA)
  69
  70typedef struct OpenFlags {
  71    const char *forms;
  72    DWORD desired_access;
  73    DWORD creation_disposition;
  74} OpenFlags;
  75static OpenFlags guest_file_open_modes[] = {
  76    {"r",   GENERIC_READ,                     OPEN_EXISTING},
  77    {"rb",  GENERIC_READ,                     OPEN_EXISTING},
  78    {"w",   GENERIC_WRITE,                    CREATE_ALWAYS},
  79    {"wb",  GENERIC_WRITE,                    CREATE_ALWAYS},
  80    {"a",   FILE_GENERIC_APPEND,              OPEN_ALWAYS  },
  81    {"r+",  GENERIC_WRITE|GENERIC_READ,       OPEN_EXISTING},
  82    {"rb+", GENERIC_WRITE|GENERIC_READ,       OPEN_EXISTING},
  83    {"r+b", GENERIC_WRITE|GENERIC_READ,       OPEN_EXISTING},
  84    {"w+",  GENERIC_WRITE|GENERIC_READ,       CREATE_ALWAYS},
  85    {"wb+", GENERIC_WRITE|GENERIC_READ,       CREATE_ALWAYS},
  86    {"w+b", GENERIC_WRITE|GENERIC_READ,       CREATE_ALWAYS},
  87    {"a+",  FILE_GENERIC_APPEND|GENERIC_READ, OPEN_ALWAYS  },
  88    {"ab+", FILE_GENERIC_APPEND|GENERIC_READ, OPEN_ALWAYS  },
  89    {"a+b", FILE_GENERIC_APPEND|GENERIC_READ, OPEN_ALWAYS  }
  90};
  91
  92#define debug_error(msg) do { \
  93    char *suffix = g_win32_error_message(GetLastError()); \
  94    g_debug("%s: %s", (msg), suffix); \
  95    g_free(suffix); \
  96} while (0)
  97
  98static OpenFlags *find_open_flag(const char *mode_str)
  99{
 100    int mode;
 101    Error **errp = NULL;
 102
 103    for (mode = 0; mode < ARRAY_SIZE(guest_file_open_modes); ++mode) {
 104        OpenFlags *flags = guest_file_open_modes + mode;
 105
 106        if (strcmp(flags->forms, mode_str) == 0) {
 107            return flags;
 108        }
 109    }
 110
 111    error_setg(errp, "invalid file open mode '%s'", mode_str);
 112    return NULL;
 113}
 114
 115static int64_t guest_file_handle_add(HANDLE fh, Error **errp)
 116{
 117    GuestFileHandle *gfh;
 118    int64_t handle;
 119
 120    handle = ga_get_fd_handle(ga_state, errp);
 121    if (handle < 0) {
 122        return -1;
 123    }
 124    gfh = g_new0(GuestFileHandle, 1);
 125    gfh->id = handle;
 126    gfh->fh = fh;
 127    QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next);
 128
 129    return handle;
 130}
 131
 132static GuestFileHandle *guest_file_handle_find(int64_t id, Error **errp)
 133{
 134    GuestFileHandle *gfh;
 135    QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next) {
 136        if (gfh->id == id) {
 137            return gfh;
 138        }
 139    }
 140    error_setg(errp, "handle '%" PRId64 "' has not been found", id);
 141    return NULL;
 142}
 143
 144static void handle_set_nonblocking(HANDLE fh)
 145{
 146    DWORD file_type, pipe_state;
 147    file_type = GetFileType(fh);
 148    if (file_type != FILE_TYPE_PIPE) {
 149        return;
 150    }
 151    /* If file_type == FILE_TYPE_PIPE, according to MSDN
 152     * the specified file is socket or named pipe */
 153    if (!GetNamedPipeHandleState(fh, &pipe_state, NULL,
 154                                 NULL, NULL, NULL, 0)) {
 155        return;
 156    }
 157    /* The fd is named pipe fd */
 158    if (pipe_state & PIPE_NOWAIT) {
 159        return;
 160    }
 161
 162    pipe_state |= PIPE_NOWAIT;
 163    SetNamedPipeHandleState(fh, &pipe_state, NULL, NULL);
 164}
 165
 166int64_t qmp_guest_file_open(const char *path, bool has_mode,
 167                            const char *mode, Error **errp)
 168{
 169    int64_t fd = -1;
 170    HANDLE fh;
 171    HANDLE templ_file = NULL;
 172    DWORD share_mode = FILE_SHARE_READ;
 173    DWORD flags_and_attr = FILE_ATTRIBUTE_NORMAL;
 174    LPSECURITY_ATTRIBUTES sa_attr = NULL;
 175    OpenFlags *guest_flags;
 176    GError *gerr = NULL;
 177    wchar_t *w_path = NULL;
 178
 179    if (!has_mode) {
 180        mode = "r";
 181    }
 182    slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
 183    guest_flags = find_open_flag(mode);
 184    if (guest_flags == NULL) {
 185        error_setg(errp, "invalid file open mode");
 186        goto done;
 187    }
 188
 189    w_path = g_utf8_to_utf16(path, -1, NULL, NULL, &gerr);
 190    if (!w_path) {
 191        goto done;
 192    }
 193
 194    fh = CreateFileW(w_path, guest_flags->desired_access, share_mode, sa_attr,
 195                    guest_flags->creation_disposition, flags_and_attr,
 196                    templ_file);
 197    if (fh == INVALID_HANDLE_VALUE) {
 198        error_setg_win32(errp, GetLastError(), "failed to open file '%s'",
 199                         path);
 200        goto done;
 201    }
 202
 203    /* set fd non-blocking to avoid common use cases (like reading from a
 204     * named pipe) from hanging the agent
 205     */
 206    handle_set_nonblocking(fh);
 207
 208    fd = guest_file_handle_add(fh, errp);
 209    if (fd < 0) {
 210        CloseHandle(fh);
 211        error_setg(errp, "failed to add handle to qmp handle table");
 212        goto done;
 213    }
 214
 215    slog("guest-file-open, handle: % " PRId64, fd);
 216
 217done:
 218    if (gerr) {
 219        error_setg(errp, QERR_QGA_COMMAND_FAILED, gerr->message);
 220        g_error_free(gerr);
 221    }
 222    g_free(w_path);
 223    return fd;
 224}
 225
 226void qmp_guest_file_close(int64_t handle, Error **errp)
 227{
 228    bool ret;
 229    GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
 230    slog("guest-file-close called, handle: %" PRId64, handle);
 231    if (gfh == NULL) {
 232        return;
 233    }
 234    ret = CloseHandle(gfh->fh);
 235    if (!ret) {
 236        error_setg_win32(errp, GetLastError(), "failed close handle");
 237        return;
 238    }
 239
 240    QTAILQ_REMOVE(&guest_file_state.filehandles, gfh, next);
 241    g_free(gfh);
 242}
 243
 244static void acquire_privilege(const char *name, Error **errp)
 245{
 246    HANDLE token = NULL;
 247    TOKEN_PRIVILEGES priv;
 248    Error *local_err = NULL;
 249
 250    if (OpenProcessToken(GetCurrentProcess(),
 251        TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &token))
 252    {
 253        if (!LookupPrivilegeValue(NULL, name, &priv.Privileges[0].Luid)) {
 254            error_setg(&local_err, QERR_QGA_COMMAND_FAILED,
 255                       "no luid for requested privilege");
 256            goto out;
 257        }
 258
 259        priv.PrivilegeCount = 1;
 260        priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
 261
 262        if (!AdjustTokenPrivileges(token, FALSE, &priv, 0, NULL, 0)) {
 263            error_setg(&local_err, QERR_QGA_COMMAND_FAILED,
 264                       "unable to acquire requested privilege");
 265            goto out;
 266        }
 267
 268    } else {
 269        error_setg(&local_err, QERR_QGA_COMMAND_FAILED,
 270                   "failed to open privilege token");
 271    }
 272
 273out:
 274    if (token) {
 275        CloseHandle(token);
 276    }
 277    error_propagate(errp, local_err);
 278}
 279
 280static void execute_async(DWORD WINAPI (*func)(LPVOID), LPVOID opaque,
 281                          Error **errp)
 282{
 283    Error *local_err = NULL;
 284
 285    HANDLE thread = CreateThread(NULL, 0, func, opaque, 0, NULL);
 286    if (!thread) {
 287        error_setg(&local_err, QERR_QGA_COMMAND_FAILED,
 288                   "failed to dispatch asynchronous command");
 289        error_propagate(errp, local_err);
 290    }
 291}
 292
 293void qmp_guest_shutdown(bool has_mode, const char *mode, Error **errp)
 294{
 295    Error *local_err = NULL;
 296    UINT shutdown_flag = EWX_FORCE;
 297
 298    slog("guest-shutdown called, mode: %s", mode);
 299
 300    if (!has_mode || strcmp(mode, "powerdown") == 0) {
 301        shutdown_flag |= EWX_POWEROFF;
 302    } else if (strcmp(mode, "halt") == 0) {
 303        shutdown_flag |= EWX_SHUTDOWN;
 304    } else if (strcmp(mode, "reboot") == 0) {
 305        shutdown_flag |= EWX_REBOOT;
 306    } else {
 307        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "mode",
 308                   "halt|powerdown|reboot");
 309        return;
 310    }
 311
 312    /* Request a shutdown privilege, but try to shut down the system
 313       anyway. */
 314    acquire_privilege(SE_SHUTDOWN_NAME, &local_err);
 315    if (local_err) {
 316        error_propagate(errp, local_err);
 317        return;
 318    }
 319
 320    if (!ExitWindowsEx(shutdown_flag, SHTDN_REASON_FLAG_PLANNED)) {
 321        slog("guest-shutdown failed: %lu", GetLastError());
 322        error_setg(errp, QERR_UNDEFINED_ERROR);
 323    }
 324}
 325
 326GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
 327                                   int64_t count, Error **errp)
 328{
 329    GuestFileRead *read_data = NULL;
 330    guchar *buf;
 331    HANDLE fh;
 332    bool is_ok;
 333    DWORD read_count;
 334    GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
 335
 336    if (!gfh) {
 337        return NULL;
 338    }
 339    if (!has_count) {
 340        count = QGA_READ_COUNT_DEFAULT;
 341    } else if (count < 0 || count >= UINT32_MAX) {
 342        error_setg(errp, "value '%" PRId64
 343                   "' is invalid for argument count", count);
 344        return NULL;
 345    }
 346
 347    fh = gfh->fh;
 348    buf = g_malloc0(count+1);
 349    is_ok = ReadFile(fh, buf, count, &read_count, NULL);
 350    if (!is_ok) {
 351        error_setg_win32(errp, GetLastError(), "failed to read file");
 352        slog("guest-file-read failed, handle %" PRId64, handle);
 353    } else {
 354        buf[read_count] = 0;
 355        read_data = g_new0(GuestFileRead, 1);
 356        read_data->count = (size_t)read_count;
 357        read_data->eof = read_count == 0;
 358
 359        if (read_count != 0) {
 360            read_data->buf_b64 = g_base64_encode(buf, read_count);
 361        }
 362    }
 363    g_free(buf);
 364
 365    return read_data;
 366}
 367
 368GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
 369                                     bool has_count, int64_t count,
 370                                     Error **errp)
 371{
 372    GuestFileWrite *write_data = NULL;
 373    guchar *buf;
 374    gsize buf_len;
 375    bool is_ok;
 376    DWORD write_count;
 377    GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
 378    HANDLE fh;
 379
 380    if (!gfh) {
 381        return NULL;
 382    }
 383    fh = gfh->fh;
 384    buf = qbase64_decode(buf_b64, -1, &buf_len, errp);
 385    if (!buf) {
 386        return NULL;
 387    }
 388
 389    if (!has_count) {
 390        count = buf_len;
 391    } else if (count < 0 || count > buf_len) {
 392        error_setg(errp, "value '%" PRId64
 393                   "' is invalid for argument count", count);
 394        goto done;
 395    }
 396
 397    is_ok = WriteFile(fh, buf, count, &write_count, NULL);
 398    if (!is_ok) {
 399        error_setg_win32(errp, GetLastError(), "failed to write to file");
 400        slog("guest-file-write-failed, handle: %" PRId64, handle);
 401    } else {
 402        write_data = g_new0(GuestFileWrite, 1);
 403        write_data->count = (size_t) write_count;
 404    }
 405
 406done:
 407    g_free(buf);
 408    return write_data;
 409}
 410
 411GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
 412                                   GuestFileWhence *whence_code,
 413                                   Error **errp)
 414{
 415    GuestFileHandle *gfh;
 416    GuestFileSeek *seek_data;
 417    HANDLE fh;
 418    LARGE_INTEGER new_pos, off_pos;
 419    off_pos.QuadPart = offset;
 420    BOOL res;
 421    int whence;
 422    Error *err = NULL;
 423
 424    gfh = guest_file_handle_find(handle, errp);
 425    if (!gfh) {
 426        return NULL;
 427    }
 428
 429    /* We stupidly exposed 'whence':'int' in our qapi */
 430    whence = ga_parse_whence(whence_code, &err);
 431    if (err) {
 432        error_propagate(errp, err);
 433        return NULL;
 434    }
 435
 436    fh = gfh->fh;
 437    res = SetFilePointerEx(fh, off_pos, &new_pos, whence);
 438    if (!res) {
 439        error_setg_win32(errp, GetLastError(), "failed to seek file");
 440        return NULL;
 441    }
 442    seek_data = g_new0(GuestFileSeek, 1);
 443    seek_data->position = new_pos.QuadPart;
 444    return seek_data;
 445}
 446
 447void qmp_guest_file_flush(int64_t handle, Error **errp)
 448{
 449    HANDLE fh;
 450    GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
 451    if (!gfh) {
 452        return;
 453    }
 454
 455    fh = gfh->fh;
 456    if (!FlushFileBuffers(fh)) {
 457        error_setg_win32(errp, GetLastError(), "failed to flush file");
 458    }
 459}
 460
 461#ifdef CONFIG_QGA_NTDDSCSI
 462
 463static STORAGE_BUS_TYPE win2qemu[] = {
 464    [BusTypeUnknown] = GUEST_DISK_BUS_TYPE_UNKNOWN,
 465    [BusTypeScsi] = GUEST_DISK_BUS_TYPE_SCSI,
 466    [BusTypeAtapi] = GUEST_DISK_BUS_TYPE_IDE,
 467    [BusTypeAta] = GUEST_DISK_BUS_TYPE_IDE,
 468    [BusType1394] = GUEST_DISK_BUS_TYPE_IEEE1394,
 469    [BusTypeSsa] = GUEST_DISK_BUS_TYPE_SSA,
 470    [BusTypeFibre] = GUEST_DISK_BUS_TYPE_SSA,
 471    [BusTypeUsb] = GUEST_DISK_BUS_TYPE_USB,
 472    [BusTypeRAID] = GUEST_DISK_BUS_TYPE_RAID,
 473#if (_WIN32_WINNT >= 0x0600)
 474    [BusTypeiScsi] = GUEST_DISK_BUS_TYPE_ISCSI,
 475    [BusTypeSas] = GUEST_DISK_BUS_TYPE_SAS,
 476    [BusTypeSata] = GUEST_DISK_BUS_TYPE_SATA,
 477    [BusTypeSd] =  GUEST_DISK_BUS_TYPE_SD,
 478    [BusTypeMmc] = GUEST_DISK_BUS_TYPE_MMC,
 479#endif
 480#if (_WIN32_WINNT >= 0x0601)
 481    [BusTypeVirtual] = GUEST_DISK_BUS_TYPE_VIRTUAL,
 482    [BusTypeFileBackedVirtual] = GUEST_DISK_BUS_TYPE_FILE_BACKED_VIRTUAL,
 483#endif
 484};
 485
 486static GuestDiskBusType find_bus_type(STORAGE_BUS_TYPE bus)
 487{
 488    if (bus >= ARRAY_SIZE(win2qemu) || (int)bus < 0) {
 489        return GUEST_DISK_BUS_TYPE_UNKNOWN;
 490    }
 491    return win2qemu[(int)bus];
 492}
 493
 494/* XXX: The following function is BROKEN!
 495 *
 496 * It does not work and probably has never worked. When we query for list of
 497 * disks we get cryptic names like "\Device\0000001d" instead of
 498 * "\PhysicalDriveX" or "\HarddiskX". Whether the names can be translated one
 499 * way or the other for comparison is an open question.
 500 *
 501 * When we query volume names (the original version) we are able to match those
 502 * but then the property queries report error "Invalid function". (duh!)
 503 */
 504
 505/*
 506DEFINE_GUID(GUID_DEVINTERFACE_VOLUME,
 507        0x53f5630dL, 0xb6bf, 0x11d0, 0x94, 0xf2,
 508        0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);
 509*/
 510DEFINE_GUID(GUID_DEVINTERFACE_DISK,
 511        0x53f56307L, 0xb6bf, 0x11d0, 0x94, 0xf2,
 512        0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);
 513
 514
 515static GuestPCIAddress *get_pci_info(char *guid, Error **errp)
 516{
 517    HDEVINFO dev_info;
 518    SP_DEVINFO_DATA dev_info_data;
 519    DWORD size = 0;
 520    int i;
 521    char dev_name[MAX_PATH];
 522    char *buffer = NULL;
 523    GuestPCIAddress *pci = NULL;
 524    char *name = NULL;
 525    bool partial_pci = false;
 526    pci = g_malloc0(sizeof(*pci));
 527    pci->domain = -1;
 528    pci->slot = -1;
 529    pci->function = -1;
 530    pci->bus = -1;
 531
 532    if (g_str_has_prefix(guid, "\\\\.\\") ||
 533        g_str_has_prefix(guid, "\\\\?\\")) {
 534        name = g_strdup(guid + 4);
 535    } else {
 536        name = g_strdup(guid);
 537    }
 538
 539    if (!QueryDosDevice(name, dev_name, ARRAY_SIZE(dev_name))) {
 540        error_setg_win32(errp, GetLastError(), "failed to get dos device name");
 541        goto out;
 542    }
 543
 544    dev_info = SetupDiGetClassDevs(&GUID_DEVINTERFACE_DISK, 0, 0,
 545                                   DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
 546    if (dev_info == INVALID_HANDLE_VALUE) {
 547        error_setg_win32(errp, GetLastError(), "failed to get devices tree");
 548        goto out;
 549    }
 550
 551    g_debug("enumerating devices");
 552    dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
 553    for (i = 0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) {
 554        DWORD addr, bus, slot, data, size2;
 555        int func, dev;
 556        while (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data,
 557                                            SPDRP_PHYSICAL_DEVICE_OBJECT_NAME,
 558                                            &data, (PBYTE)buffer, size,
 559                                            &size2)) {
 560            size = MAX(size, size2);
 561            if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
 562                g_free(buffer);
 563                /* Double the size to avoid problems on
 564                 * W2k MBCS systems per KB 888609.
 565                 * https://support.microsoft.com/en-us/kb/259695 */
 566                buffer = g_malloc(size * 2);
 567            } else {
 568                error_setg_win32(errp, GetLastError(),
 569                        "failed to get device name");
 570                goto free_dev_info;
 571            }
 572        }
 573
 574        if (g_strcmp0(buffer, dev_name)) {
 575            continue;
 576        }
 577        g_debug("found device %s", dev_name);
 578
 579        /* There is no need to allocate buffer in the next functions. The size
 580         * is known and ULONG according to
 581         * https://support.microsoft.com/en-us/kb/253232
 582         * https://msdn.microsoft.com/en-us/library/windows/hardware/ff543095(v=vs.85).aspx
 583         */
 584        if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data,
 585                   SPDRP_BUSNUMBER, &data, (PBYTE)&bus, size, NULL)) {
 586            debug_error("failed to get bus");
 587            bus = -1;
 588            partial_pci = true;
 589        }
 590
 591        /* The function retrieves the device's address. This value will be
 592         * transformed into device function and number */
 593        if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data,
 594                   SPDRP_ADDRESS, &data, (PBYTE)&addr, size, NULL)) {
 595            debug_error("failed to get address");
 596            addr = -1;
 597            partial_pci = true;
 598        }
 599
 600        /* This call returns UINumber of DEVICE_CAPABILITIES structure.
 601         * This number is typically a user-perceived slot number. */
 602        if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data,
 603                   SPDRP_UI_NUMBER, &data, (PBYTE)&slot, size, NULL)) {
 604            debug_error("failed to get slot");
 605            slot = -1;
 606            partial_pci = true;
 607        }
 608
 609        /* SetupApi gives us the same information as driver with
 610         * IoGetDeviceProperty. According to Microsoft
 611         * https://support.microsoft.com/en-us/kb/253232
 612         * FunctionNumber = (USHORT)((propertyAddress) & 0x0000FFFF);
 613         * DeviceNumber = (USHORT)(((propertyAddress) >> 16) & 0x0000FFFF);
 614         * SPDRP_ADDRESS is propertyAddress, so we do the same.*/
 615
 616        if (partial_pci) {
 617            pci->domain = -1;
 618            pci->slot = -1;
 619            pci->function = -1;
 620            pci->bus = -1;
 621        } else {
 622            func = ((int) addr == -1) ? -1 : addr & 0x0000FFFF;
 623            dev = ((int) addr == -1) ? -1 : (addr >> 16) & 0x0000FFFF;
 624            pci->domain = dev;
 625            pci->slot = (int) slot;
 626            pci->function = func;
 627            pci->bus = (int) bus;
 628        }
 629        break;
 630    }
 631
 632free_dev_info:
 633    SetupDiDestroyDeviceInfoList(dev_info);
 634out:
 635    g_free(buffer);
 636    g_free(name);
 637    return pci;
 638}
 639
 640static void get_disk_properties(HANDLE vol_h, GuestDiskAddress *disk,
 641    Error **errp)
 642{
 643    STORAGE_PROPERTY_QUERY query;
 644    STORAGE_DEVICE_DESCRIPTOR *dev_desc, buf;
 645    DWORD received;
 646    ULONG size = sizeof(buf);
 647
 648    dev_desc = &buf;
 649    query.PropertyId = StorageDeviceProperty;
 650    query.QueryType = PropertyStandardQuery;
 651
 652    if (!DeviceIoControl(vol_h, IOCTL_STORAGE_QUERY_PROPERTY, &query,
 653                         sizeof(STORAGE_PROPERTY_QUERY), dev_desc,
 654                         size, &received, NULL)) {
 655        error_setg_win32(errp, GetLastError(), "failed to get bus type");
 656        return;
 657    }
 658    disk->bus_type = find_bus_type(dev_desc->BusType);
 659    g_debug("bus type %d", disk->bus_type);
 660
 661    /* Query once more. Now with long enough buffer. */
 662    size = dev_desc->Size;
 663    dev_desc = g_malloc0(size);
 664    if (!DeviceIoControl(vol_h, IOCTL_STORAGE_QUERY_PROPERTY, &query,
 665                         sizeof(STORAGE_PROPERTY_QUERY), dev_desc,
 666                         size, &received, NULL)) {
 667        error_setg_win32(errp, GetLastError(), "failed to get serial number");
 668        g_debug("failed to get serial number");
 669        goto out_free;
 670    }
 671    if (dev_desc->SerialNumberOffset > 0) {
 672        const char *serial;
 673        size_t len;
 674
 675        if (dev_desc->SerialNumberOffset >= received) {
 676            error_setg(errp, "failed to get serial number: offset outside the buffer");
 677            g_debug("serial number offset outside the buffer");
 678            goto out_free;
 679        }
 680        serial = (char *)dev_desc + dev_desc->SerialNumberOffset;
 681        len = received - dev_desc->SerialNumberOffset;
 682        g_debug("serial number \"%s\"", serial);
 683        if (*serial != 0) {
 684            disk->serial = g_strndup(serial, len);
 685            disk->has_serial = true;
 686        }
 687    }
 688out_free:
 689    g_free(dev_desc);
 690
 691    return;
 692}
 693
 694static void get_single_disk_info(GuestDiskAddress *disk, Error **errp)
 695{
 696    SCSI_ADDRESS addr, *scsi_ad;
 697    DWORD len;
 698    HANDLE disk_h;
 699    Error *local_err = NULL;
 700
 701    scsi_ad = &addr;
 702
 703    g_debug("getting disk info for: %s", disk->dev);
 704    disk_h = CreateFile(disk->dev, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
 705                       0, NULL);
 706    if (disk_h == INVALID_HANDLE_VALUE) {
 707        error_setg_win32(errp, GetLastError(), "failed to open disk");
 708        return;
 709    }
 710
 711    get_disk_properties(disk_h, disk, &local_err);
 712    if (local_err) {
 713        error_propagate(errp, local_err);
 714        goto err_close;
 715    }
 716
 717    g_debug("bus type %d", disk->bus_type);
 718    /* always set pci_controller as required by schema. get_pci_info() should
 719     * report -1 values for non-PCI buses rather than fail. fail the command
 720     * if that doesn't hold since that suggests some other unexpected
 721     * breakage
 722     */
 723    disk->pci_controller = get_pci_info(disk->dev, &local_err);
 724    if (local_err) {
 725        error_propagate(errp, local_err);
 726        goto err_close;
 727    }
 728    if (disk->bus_type == GUEST_DISK_BUS_TYPE_SCSI
 729            || disk->bus_type == GUEST_DISK_BUS_TYPE_IDE
 730            || disk->bus_type == GUEST_DISK_BUS_TYPE_RAID
 731#if (_WIN32_WINNT >= 0x0600)
 732            /* This bus type is not supported before Windows Server 2003 SP1 */
 733            || disk->bus_type == GUEST_DISK_BUS_TYPE_SAS
 734#endif
 735        ) {
 736        /* We are able to use the same ioctls for different bus types
 737         * according to Microsoft docs
 738         * https://technet.microsoft.com/en-us/library/ee851589(v=ws.10).aspx */
 739        g_debug("getting pci-controller info");
 740        if (DeviceIoControl(disk_h, IOCTL_SCSI_GET_ADDRESS, NULL, 0, scsi_ad,
 741                            sizeof(SCSI_ADDRESS), &len, NULL)) {
 742            disk->unit = addr.Lun;
 743            disk->target = addr.TargetId;
 744            disk->bus = addr.PathId;
 745        }
 746        /* We do not set error in this case, because we still have enough
 747         * information about volume. */
 748    }
 749
 750err_close:
 751    CloseHandle(disk_h);
 752    return;
 753}
 754
 755/* VSS provider works with volumes, thus there is no difference if
 756 * the volume consist of spanned disks. Info about the first disk in the
 757 * volume is returned for the spanned disk group (LVM) */
 758static GuestDiskAddressList *build_guest_disk_info(char *guid, Error **errp)
 759{
 760    Error *local_err = NULL;
 761    GuestDiskAddressList *list = NULL, *cur_item = NULL;
 762    GuestDiskAddress *disk = NULL;
 763    int i;
 764    HANDLE vol_h;
 765    DWORD size;
 766    PVOLUME_DISK_EXTENTS extents = NULL;
 767
 768    /* strip final backslash */
 769    char *name = g_strdup(guid);
 770    if (g_str_has_suffix(name, "\\")) {
 771        name[strlen(name) - 1] = 0;
 772    }
 773
 774    g_debug("opening %s", name);
 775    vol_h = CreateFile(name, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
 776                       0, NULL);
 777    if (vol_h == INVALID_HANDLE_VALUE) {
 778        error_setg_win32(errp, GetLastError(), "failed to open volume");
 779        goto out;
 780    }
 781
 782    /* Get list of extents */
 783    g_debug("getting disk extents");
 784    size = sizeof(VOLUME_DISK_EXTENTS);
 785    extents = g_malloc0(size);
 786    if (!DeviceIoControl(vol_h, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL,
 787                         0, extents, size, NULL, NULL)) {
 788        DWORD last_err = GetLastError();
 789        if (last_err == ERROR_MORE_DATA) {
 790            /* Try once more with big enough buffer */
 791            size = sizeof(VOLUME_DISK_EXTENTS)
 792                + extents->NumberOfDiskExtents*sizeof(DISK_EXTENT);
 793            g_free(extents);
 794            extents = g_malloc0(size);
 795            if (!DeviceIoControl(
 796                    vol_h, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL,
 797                    0, extents, size, NULL, NULL)) {
 798                error_setg_win32(errp, GetLastError(),
 799                    "failed to get disk extents");
 800                goto out;
 801            }
 802        } else if (last_err == ERROR_INVALID_FUNCTION) {
 803            /* Possibly CD-ROM or a shared drive. Try to pass the volume */
 804            g_debug("volume not on disk");
 805            disk = g_malloc0(sizeof(GuestDiskAddress));
 806            disk->has_dev = true;
 807            disk->dev = g_strdup(name);
 808            get_single_disk_info(disk, &local_err);
 809            if (local_err) {
 810                g_debug("failed to get disk info, ignoring error: %s",
 811                    error_get_pretty(local_err));
 812                error_free(local_err);
 813                goto out;
 814            }
 815            list = g_malloc0(sizeof(*list));
 816            list->value = disk;
 817            disk = NULL;
 818            list->next = NULL;
 819            goto out;
 820        } else {
 821            error_setg_win32(errp, GetLastError(),
 822                "failed to get disk extents");
 823            goto out;
 824        }
 825    }
 826    g_debug("Number of extents: %lu", extents->NumberOfDiskExtents);
 827
 828    /* Go through each extent */
 829    for (i = 0; i < extents->NumberOfDiskExtents; i++) {
 830        disk = g_malloc0(sizeof(GuestDiskAddress));
 831
 832        /* Disk numbers directly correspond to numbers used in UNCs
 833         *
 834         * See documentation for DISK_EXTENT:
 835         * https://docs.microsoft.com/en-us/windows/desktop/api/winioctl/ns-winioctl-_disk_extent
 836         *
 837         * See also Naming Files, Paths and Namespaces:
 838         * https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#win32-device-namespaces
 839         */
 840        disk->has_dev = true;
 841        disk->dev = g_strdup_printf("\\\\.\\PhysicalDrive%lu",
 842            extents->Extents[i].DiskNumber);
 843
 844        get_single_disk_info(disk, &local_err);
 845        if (local_err) {
 846            error_propagate(errp, local_err);
 847            goto out;
 848        }
 849        cur_item = g_malloc0(sizeof(*list));
 850        cur_item->value = disk;
 851        disk = NULL;
 852        cur_item->next = list;
 853        list = cur_item;
 854    }
 855
 856
 857out:
 858    if (vol_h != INVALID_HANDLE_VALUE) {
 859        CloseHandle(vol_h);
 860    }
 861    qapi_free_GuestDiskAddress(disk);
 862    g_free(extents);
 863    g_free(name);
 864
 865    return list;
 866}
 867
 868#else
 869
 870static GuestDiskAddressList *build_guest_disk_info(char *guid, Error **errp)
 871{
 872    return NULL;
 873}
 874
 875#endif /* CONFIG_QGA_NTDDSCSI */
 876
 877static GuestFilesystemInfo *build_guest_fsinfo(char *guid, Error **errp)
 878{
 879    DWORD info_size;
 880    char mnt, *mnt_point;
 881    char fs_name[32];
 882    char vol_info[MAX_PATH+1];
 883    size_t len;
 884    uint64_t i64FreeBytesToCaller, i64TotalBytes, i64FreeBytes;
 885    GuestFilesystemInfo *fs = NULL;
 886
 887    GetVolumePathNamesForVolumeName(guid, (LPCH)&mnt, 0, &info_size);
 888    if (GetLastError() != ERROR_MORE_DATA) {
 889        error_setg_win32(errp, GetLastError(), "failed to get volume name");
 890        return NULL;
 891    }
 892
 893    mnt_point = g_malloc(info_size + 1);
 894    if (!GetVolumePathNamesForVolumeName(guid, mnt_point, info_size,
 895                                         &info_size)) {
 896        error_setg_win32(errp, GetLastError(), "failed to get volume name");
 897        goto free;
 898    }
 899
 900    len = strlen(mnt_point);
 901    mnt_point[len] = '\\';
 902    mnt_point[len+1] = 0;
 903    if (!GetVolumeInformation(mnt_point, vol_info, sizeof(vol_info), NULL, NULL,
 904                              NULL, (LPSTR)&fs_name, sizeof(fs_name))) {
 905        if (GetLastError() != ERROR_NOT_READY) {
 906            error_setg_win32(errp, GetLastError(), "failed to get volume info");
 907        }
 908        goto free;
 909    }
 910
 911    fs_name[sizeof(fs_name) - 1] = 0;
 912    fs = g_malloc(sizeof(*fs));
 913    fs->name = g_strdup(guid);
 914    fs->has_total_bytes = false;
 915    fs->has_used_bytes = false;
 916    if (len == 0) {
 917        fs->mountpoint = g_strdup("System Reserved");
 918    } else {
 919        fs->mountpoint = g_strndup(mnt_point, len);
 920        if (GetDiskFreeSpaceEx(fs->mountpoint,
 921                               (PULARGE_INTEGER) & i64FreeBytesToCaller,
 922                               (PULARGE_INTEGER) & i64TotalBytes,
 923                               (PULARGE_INTEGER) & i64FreeBytes)) {
 924            fs->used_bytes = i64TotalBytes - i64FreeBytes;
 925            fs->total_bytes = i64TotalBytes;
 926            fs->has_total_bytes = true;
 927            fs->has_used_bytes = true;
 928        }
 929    }
 930    fs->type = g_strdup(fs_name);
 931    fs->disk = build_guest_disk_info(guid, errp);
 932free:
 933    g_free(mnt_point);
 934    return fs;
 935}
 936
 937GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
 938{
 939    HANDLE vol_h;
 940    GuestFilesystemInfoList *new, *ret = NULL;
 941    char guid[256];
 942
 943    vol_h = FindFirstVolume(guid, sizeof(guid));
 944    if (vol_h == INVALID_HANDLE_VALUE) {
 945        error_setg_win32(errp, GetLastError(), "failed to find any volume");
 946        return NULL;
 947    }
 948
 949    do {
 950        GuestFilesystemInfo *info = build_guest_fsinfo(guid, errp);
 951        if (info == NULL) {
 952            continue;
 953        }
 954        new = g_malloc(sizeof(*ret));
 955        new->value = info;
 956        new->next = ret;
 957        ret = new;
 958    } while (FindNextVolume(vol_h, guid, sizeof(guid)));
 959
 960    if (GetLastError() != ERROR_NO_MORE_FILES) {
 961        error_setg_win32(errp, GetLastError(), "failed to find next volume");
 962    }
 963
 964    FindVolumeClose(vol_h);
 965    return ret;
 966}
 967
 968/*
 969 * Return status of freeze/thaw
 970 */
 971GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
 972{
 973    if (!vss_initialized()) {
 974        error_setg(errp, QERR_UNSUPPORTED);
 975        return 0;
 976    }
 977
 978    if (ga_is_frozen(ga_state)) {
 979        return GUEST_FSFREEZE_STATUS_FROZEN;
 980    }
 981
 982    return GUEST_FSFREEZE_STATUS_THAWED;
 983}
 984
 985/*
 986 * Freeze local file systems using Volume Shadow-copy Service.
 987 * The frozen state is limited for up to 10 seconds by VSS.
 988 */
 989int64_t qmp_guest_fsfreeze_freeze(Error **errp)
 990{
 991    return qmp_guest_fsfreeze_freeze_list(false, NULL, errp);
 992}
 993
 994int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
 995                                       strList *mountpoints,
 996                                       Error **errp)
 997{
 998    int i;
 999    Error *local_err = NULL;
1000
1001    if (!vss_initialized()) {
1002        error_setg(errp, QERR_UNSUPPORTED);
1003        return 0;
1004    }
1005
1006    slog("guest-fsfreeze called");
1007
1008    /* cannot risk guest agent blocking itself on a write in this state */
1009    ga_set_frozen(ga_state);
1010
1011    qga_vss_fsfreeze(&i, true, mountpoints, &local_err);
1012    if (local_err) {
1013        error_propagate(errp, local_err);
1014        goto error;
1015    }
1016
1017    return i;
1018
1019error:
1020    local_err = NULL;
1021    qmp_guest_fsfreeze_thaw(&local_err);
1022    if (local_err) {
1023        g_debug("cleanup thaw: %s", error_get_pretty(local_err));
1024        error_free(local_err);
1025    }
1026    return 0;
1027}
1028
1029/*
1030 * Thaw local file systems using Volume Shadow-copy Service.
1031 */
1032int64_t qmp_guest_fsfreeze_thaw(Error **errp)
1033{
1034    int i;
1035
1036    if (!vss_initialized()) {
1037        error_setg(errp, QERR_UNSUPPORTED);
1038        return 0;
1039    }
1040
1041    qga_vss_fsfreeze(&i, false, NULL, errp);
1042
1043    ga_unset_frozen(ga_state);
1044    return i;
1045}
1046
1047static void guest_fsfreeze_cleanup(void)
1048{
1049    Error *err = NULL;
1050
1051    if (!vss_initialized()) {
1052        return;
1053    }
1054
1055    if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) {
1056        qmp_guest_fsfreeze_thaw(&err);
1057        if (err) {
1058            slog("failed to clean up frozen filesystems: %s",
1059                 error_get_pretty(err));
1060            error_free(err);
1061        }
1062    }
1063
1064    vss_deinit(true);
1065}
1066
1067/*
1068 * Walk list of mounted file systems in the guest, and discard unused
1069 * areas.
1070 */
1071GuestFilesystemTrimResponse *
1072qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
1073{
1074    GuestFilesystemTrimResponse *resp;
1075    HANDLE handle;
1076    WCHAR guid[MAX_PATH] = L"";
1077    OSVERSIONINFO osvi;
1078    BOOL win8_or_later;
1079
1080    ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
1081    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1082    GetVersionEx(&osvi);
1083    win8_or_later = (osvi.dwMajorVersion > 6 ||
1084                          ((osvi.dwMajorVersion == 6) &&
1085                           (osvi.dwMinorVersion >= 2)));
1086    if (!win8_or_later) {
1087        error_setg(errp, "fstrim is only supported for Win8+");
1088        return NULL;
1089    }
1090
1091    handle = FindFirstVolumeW(guid, ARRAYSIZE(guid));
1092    if (handle == INVALID_HANDLE_VALUE) {
1093        error_setg_win32(errp, GetLastError(), "failed to find any volume");
1094        return NULL;
1095    }
1096
1097    resp = g_new0(GuestFilesystemTrimResponse, 1);
1098
1099    do {
1100        GuestFilesystemTrimResult *res;
1101        GuestFilesystemTrimResultList *list;
1102        PWCHAR uc_path;
1103        DWORD char_count = 0;
1104        char *path, *out;
1105        GError *gerr = NULL;
1106        gchar * argv[4];
1107
1108        GetVolumePathNamesForVolumeNameW(guid, NULL, 0, &char_count);
1109
1110        if (GetLastError() != ERROR_MORE_DATA) {
1111            continue;
1112        }
1113        if (GetDriveTypeW(guid) != DRIVE_FIXED) {
1114            continue;
1115        }
1116
1117        uc_path = g_malloc(sizeof(WCHAR) * char_count);
1118        if (!GetVolumePathNamesForVolumeNameW(guid, uc_path, char_count,
1119                                              &char_count) || !*uc_path) {
1120            /* strange, but this condition could be faced even with size == 2 */
1121            g_free(uc_path);
1122            continue;
1123        }
1124
1125        res = g_new0(GuestFilesystemTrimResult, 1);
1126
1127        path = g_utf16_to_utf8(uc_path, char_count, NULL, NULL, &gerr);
1128
1129        g_free(uc_path);
1130
1131        if (!path) {
1132            res->has_error = true;
1133            res->error = g_strdup(gerr->message);
1134            g_error_free(gerr);
1135            break;
1136        }
1137
1138        res->path = path;
1139
1140        list = g_new0(GuestFilesystemTrimResultList, 1);
1141        list->value = res;
1142        list->next = resp->paths;
1143
1144        resp->paths = list;
1145
1146        memset(argv, 0, sizeof(argv));
1147        argv[0] = (gchar *)"defrag.exe";
1148        argv[1] = (gchar *)"/L";
1149        argv[2] = path;
1150
1151        if (!g_spawn_sync(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
1152                          &out /* stdout */, NULL /* stdin */,
1153                          NULL, &gerr)) {
1154            res->has_error = true;
1155            res->error = g_strdup(gerr->message);
1156            g_error_free(gerr);
1157        } else {
1158            /* defrag.exe is UGLY. Exit code is ALWAYS zero.
1159               Error is reported in the output with something like
1160               (x89000020) etc code in the stdout */
1161
1162            int i;
1163            gchar **lines = g_strsplit(out, "\r\n", 0);
1164            g_free(out);
1165
1166            for (i = 0; lines[i] != NULL; i++) {
1167                if (g_strstr_len(lines[i], -1, "(0x") == NULL) {
1168                    continue;
1169                }
1170                res->has_error = true;
1171                res->error = g_strdup(lines[i]);
1172                break;
1173            }
1174            g_strfreev(lines);
1175        }
1176    } while (FindNextVolumeW(handle, guid, ARRAYSIZE(guid)));
1177
1178    FindVolumeClose(handle);
1179    return resp;
1180}
1181
1182typedef enum {
1183    GUEST_SUSPEND_MODE_DISK,
1184    GUEST_SUSPEND_MODE_RAM
1185} GuestSuspendMode;
1186
1187static void check_suspend_mode(GuestSuspendMode mode, Error **errp)
1188{
1189    SYSTEM_POWER_CAPABILITIES sys_pwr_caps;
1190    Error *local_err = NULL;
1191
1192    ZeroMemory(&sys_pwr_caps, sizeof(sys_pwr_caps));
1193    if (!GetPwrCapabilities(&sys_pwr_caps)) {
1194        error_setg(&local_err, QERR_QGA_COMMAND_FAILED,
1195                   "failed to determine guest suspend capabilities");
1196        goto out;
1197    }
1198
1199    switch (mode) {
1200    case GUEST_SUSPEND_MODE_DISK:
1201        if (!sys_pwr_caps.SystemS4) {
1202            error_setg(&local_err, QERR_QGA_COMMAND_FAILED,
1203                       "suspend-to-disk not supported by OS");
1204        }
1205        break;
1206    case GUEST_SUSPEND_MODE_RAM:
1207        if (!sys_pwr_caps.SystemS3) {
1208            error_setg(&local_err, QERR_QGA_COMMAND_FAILED,
1209                       "suspend-to-ram not supported by OS");
1210        }
1211        break;
1212    default:
1213        error_setg(&local_err, QERR_INVALID_PARAMETER_VALUE, "mode",
1214                   "GuestSuspendMode");
1215    }
1216
1217out:
1218    error_propagate(errp, local_err);
1219}
1220
1221static DWORD WINAPI do_suspend(LPVOID opaque)
1222{
1223    GuestSuspendMode *mode = opaque;
1224    DWORD ret = 0;
1225
1226    if (!SetSuspendState(*mode == GUEST_SUSPEND_MODE_DISK, TRUE, TRUE)) {
1227        slog("failed to suspend guest, %lu", GetLastError());
1228        ret = -1;
1229    }
1230    g_free(mode);
1231    return ret;
1232}
1233
1234void qmp_guest_suspend_disk(Error **errp)
1235{
1236    Error *local_err = NULL;
1237    GuestSuspendMode *mode = g_new(GuestSuspendMode, 1);
1238
1239    *mode = GUEST_SUSPEND_MODE_DISK;
1240    check_suspend_mode(*mode, &local_err);
1241    acquire_privilege(SE_SHUTDOWN_NAME, &local_err);
1242    execute_async(do_suspend, mode, &local_err);
1243
1244    if (local_err) {
1245        error_propagate(errp, local_err);
1246        g_free(mode);
1247    }
1248}
1249
1250void qmp_guest_suspend_ram(Error **errp)
1251{
1252    Error *local_err = NULL;
1253    GuestSuspendMode *mode = g_new(GuestSuspendMode, 1);
1254
1255    *mode = GUEST_SUSPEND_MODE_RAM;
1256    check_suspend_mode(*mode, &local_err);
1257    acquire_privilege(SE_SHUTDOWN_NAME, &local_err);
1258    execute_async(do_suspend, mode, &local_err);
1259
1260    if (local_err) {
1261        error_propagate(errp, local_err);
1262        g_free(mode);
1263    }
1264}
1265
1266void qmp_guest_suspend_hybrid(Error **errp)
1267{
1268    error_setg(errp, QERR_UNSUPPORTED);
1269}
1270
1271static IP_ADAPTER_ADDRESSES *guest_get_adapters_addresses(Error **errp)
1272{
1273    IP_ADAPTER_ADDRESSES *adptr_addrs = NULL;
1274    ULONG adptr_addrs_len = 0;
1275    DWORD ret;
1276
1277    /* Call the first time to get the adptr_addrs_len. */
1278    GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX,
1279                         NULL, adptr_addrs, &adptr_addrs_len);
1280
1281    adptr_addrs = g_malloc(adptr_addrs_len);
1282    ret = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX,
1283                               NULL, adptr_addrs, &adptr_addrs_len);
1284    if (ret != ERROR_SUCCESS) {
1285        error_setg_win32(errp, ret, "failed to get adapters addresses");
1286        g_free(adptr_addrs);
1287        adptr_addrs = NULL;
1288    }
1289    return adptr_addrs;
1290}
1291
1292static char *guest_wctomb_dup(WCHAR *wstr)
1293{
1294    char *str;
1295    size_t i;
1296
1297    i = wcslen(wstr) + 1;
1298    str = g_malloc(i);
1299    WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK,
1300                        wstr, -1, str, i, NULL, NULL);
1301    return str;
1302}
1303
1304static char *guest_addr_to_str(IP_ADAPTER_UNICAST_ADDRESS *ip_addr,
1305                               Error **errp)
1306{
1307    char addr_str[INET6_ADDRSTRLEN + INET_ADDRSTRLEN];
1308    DWORD len;
1309    int ret;
1310
1311    if (ip_addr->Address.lpSockaddr->sa_family == AF_INET ||
1312            ip_addr->Address.lpSockaddr->sa_family == AF_INET6) {
1313        len = sizeof(addr_str);
1314        ret = WSAAddressToString(ip_addr->Address.lpSockaddr,
1315                                 ip_addr->Address.iSockaddrLength,
1316                                 NULL,
1317                                 addr_str,
1318                                 &len);
1319        if (ret != 0) {
1320            error_setg_win32(errp, WSAGetLastError(),
1321                "failed address presentation form conversion");
1322            return NULL;
1323        }
1324        return g_strdup(addr_str);
1325    }
1326    return NULL;
1327}
1328
1329#if (_WIN32_WINNT >= 0x0600)
1330static int64_t guest_ip_prefix(IP_ADAPTER_UNICAST_ADDRESS *ip_addr)
1331{
1332    /* For Windows Vista/2008 and newer, use the OnLinkPrefixLength
1333     * field to obtain the prefix.
1334     */
1335    return ip_addr->OnLinkPrefixLength;
1336}
1337#else
1338/* When using the Windows XP and 2003 build environment, do the best we can to
1339 * figure out the prefix.
1340 */
1341static IP_ADAPTER_INFO *guest_get_adapters_info(void)
1342{
1343    IP_ADAPTER_INFO *adptr_info = NULL;
1344    ULONG adptr_info_len = 0;
1345    DWORD ret;
1346
1347    /* Call the first time to get the adptr_info_len. */
1348    GetAdaptersInfo(adptr_info, &adptr_info_len);
1349
1350    adptr_info = g_malloc(adptr_info_len);
1351    ret = GetAdaptersInfo(adptr_info, &adptr_info_len);
1352    if (ret != ERROR_SUCCESS) {
1353        g_free(adptr_info);
1354        adptr_info = NULL;
1355    }
1356    return adptr_info;
1357}
1358
1359static int64_t guest_ip_prefix(IP_ADAPTER_UNICAST_ADDRESS *ip_addr)
1360{
1361    int64_t prefix = -1; /* Use for AF_INET6 and unknown/undetermined values. */
1362    IP_ADAPTER_INFO *adptr_info, *info;
1363    IP_ADDR_STRING *ip;
1364    struct in_addr *p;
1365
1366    if (ip_addr->Address.lpSockaddr->sa_family != AF_INET) {
1367        return prefix;
1368    }
1369    adptr_info = guest_get_adapters_info();
1370    if (adptr_info == NULL) {
1371        return prefix;
1372    }
1373
1374    /* Match up the passed in ip_addr with one found in adaptr_info.
1375     * The matching one in adptr_info will have the netmask.
1376     */
1377    p = &((struct sockaddr_in *)ip_addr->Address.lpSockaddr)->sin_addr;
1378    for (info = adptr_info; info; info = info->Next) {
1379        for (ip = &info->IpAddressList; ip; ip = ip->Next) {
1380            if (p->S_un.S_addr == inet_addr(ip->IpAddress.String)) {
1381                prefix = ctpop32(inet_addr(ip->IpMask.String));
1382                goto out;
1383            }
1384        }
1385    }
1386out:
1387    g_free(adptr_info);
1388    return prefix;
1389}
1390#endif
1391
1392#define INTERFACE_PATH_BUF_SZ 512
1393
1394static DWORD get_interface_index(const char *guid)
1395{
1396    ULONG index;
1397    DWORD status;
1398    wchar_t wbuf[INTERFACE_PATH_BUF_SZ];
1399    snwprintf(wbuf, INTERFACE_PATH_BUF_SZ, L"\\device\\tcpip_%s", guid);
1400    wbuf[INTERFACE_PATH_BUF_SZ - 1] = 0;
1401    status = GetAdapterIndex (wbuf, &index);
1402    if (status != NO_ERROR) {
1403        return (DWORD)~0;
1404    } else {
1405        return index;
1406    }
1407}
1408
1409typedef NETIOAPI_API (WINAPI *GetIfEntry2Func)(PMIB_IF_ROW2 Row);
1410
1411static int guest_get_network_stats(const char *name,
1412                                   GuestNetworkInterfaceStat *stats)
1413{
1414    OSVERSIONINFO os_ver;
1415
1416    os_ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1417    GetVersionEx(&os_ver);
1418    if (os_ver.dwMajorVersion >= 6) {
1419        MIB_IF_ROW2 a_mid_ifrow;
1420        GetIfEntry2Func getifentry2_ex;
1421        DWORD if_index = 0;
1422        HMODULE module = GetModuleHandle("iphlpapi");
1423        PVOID func = GetProcAddress(module, "GetIfEntry2");
1424
1425        if (func == NULL) {
1426            return -1;
1427        }
1428
1429        getifentry2_ex = (GetIfEntry2Func)func;
1430        if_index = get_interface_index(name);
1431        if (if_index == (DWORD)~0) {
1432            return -1;
1433        }
1434
1435        memset(&a_mid_ifrow, 0, sizeof(a_mid_ifrow));
1436        a_mid_ifrow.InterfaceIndex = if_index;
1437        if (NO_ERROR == getifentry2_ex(&a_mid_ifrow)) {
1438            stats->rx_bytes = a_mid_ifrow.InOctets;
1439            stats->rx_packets = a_mid_ifrow.InUcastPkts;
1440            stats->rx_errs = a_mid_ifrow.InErrors;
1441            stats->rx_dropped = a_mid_ifrow.InDiscards;
1442            stats->tx_bytes = a_mid_ifrow.OutOctets;
1443            stats->tx_packets = a_mid_ifrow.OutUcastPkts;
1444            stats->tx_errs = a_mid_ifrow.OutErrors;
1445            stats->tx_dropped = a_mid_ifrow.OutDiscards;
1446            return 0;
1447        }
1448    }
1449    return -1;
1450}
1451
1452GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
1453{
1454    IP_ADAPTER_ADDRESSES *adptr_addrs, *addr;
1455    IP_ADAPTER_UNICAST_ADDRESS *ip_addr = NULL;
1456    GuestNetworkInterfaceList *head = NULL, *cur_item = NULL;
1457    GuestIpAddressList *head_addr, *cur_addr;
1458    GuestNetworkInterfaceList *info;
1459    GuestNetworkInterfaceStat *interface_stat = NULL;
1460    GuestIpAddressList *address_item = NULL;
1461    unsigned char *mac_addr;
1462    char *addr_str;
1463    WORD wsa_version;
1464    WSADATA wsa_data;
1465    int ret;
1466
1467    adptr_addrs = guest_get_adapters_addresses(errp);
1468    if (adptr_addrs == NULL) {
1469        return NULL;
1470    }
1471
1472    /* Make WSA APIs available. */
1473    wsa_version = MAKEWORD(2, 2);
1474    ret = WSAStartup(wsa_version, &wsa_data);
1475    if (ret != 0) {
1476        error_setg_win32(errp, ret, "failed socket startup");
1477        goto out;
1478    }
1479
1480    for (addr = adptr_addrs; addr; addr = addr->Next) {
1481        info = g_malloc0(sizeof(*info));
1482
1483        if (cur_item == NULL) {
1484            head = cur_item = info;
1485        } else {
1486            cur_item->next = info;
1487            cur_item = info;
1488        }
1489
1490        info->value = g_malloc0(sizeof(*info->value));
1491        info->value->name = guest_wctomb_dup(addr->FriendlyName);
1492
1493        if (addr->PhysicalAddressLength != 0) {
1494            mac_addr = addr->PhysicalAddress;
1495
1496            info->value->hardware_address =
1497                g_strdup_printf("%02x:%02x:%02x:%02x:%02x:%02x",
1498                                (int) mac_addr[0], (int) mac_addr[1],
1499                                (int) mac_addr[2], (int) mac_addr[3],
1500                                (int) mac_addr[4], (int) mac_addr[5]);
1501
1502            info->value->has_hardware_address = true;
1503        }
1504
1505        head_addr = NULL;
1506        cur_addr = NULL;
1507        for (ip_addr = addr->FirstUnicastAddress;
1508                ip_addr;
1509                ip_addr = ip_addr->Next) {
1510            addr_str = guest_addr_to_str(ip_addr, errp);
1511            if (addr_str == NULL) {
1512                continue;
1513            }
1514
1515            address_item = g_malloc0(sizeof(*address_item));
1516
1517            if (!cur_addr) {
1518                head_addr = cur_addr = address_item;
1519            } else {
1520                cur_addr->next = address_item;
1521                cur_addr = address_item;
1522            }
1523
1524            address_item->value = g_malloc0(sizeof(*address_item->value));
1525            address_item->value->ip_address = addr_str;
1526            address_item->value->prefix = guest_ip_prefix(ip_addr);
1527            if (ip_addr->Address.lpSockaddr->sa_family == AF_INET) {
1528                address_item->value->ip_address_type =
1529                    GUEST_IP_ADDRESS_TYPE_IPV4;
1530            } else if (ip_addr->Address.lpSockaddr->sa_family == AF_INET6) {
1531                address_item->value->ip_address_type =
1532                    GUEST_IP_ADDRESS_TYPE_IPV6;
1533            }
1534        }
1535        if (head_addr) {
1536            info->value->has_ip_addresses = true;
1537            info->value->ip_addresses = head_addr;
1538        }
1539        if (!info->value->has_statistics) {
1540            interface_stat = g_malloc0(sizeof(*interface_stat));
1541            if (guest_get_network_stats(addr->AdapterName,
1542                interface_stat) == -1) {
1543                info->value->has_statistics = false;
1544                g_free(interface_stat);
1545            } else {
1546                info->value->statistics = interface_stat;
1547                info->value->has_statistics = true;
1548            }
1549        }
1550    }
1551    WSACleanup();
1552out:
1553    g_free(adptr_addrs);
1554    return head;
1555}
1556
1557int64_t qmp_guest_get_time(Error **errp)
1558{
1559    SYSTEMTIME ts = {0};
1560    FILETIME tf;
1561
1562    GetSystemTime(&ts);
1563    if (ts.wYear < 1601 || ts.wYear > 30827) {
1564        error_setg(errp, "Failed to get time");
1565        return -1;
1566    }
1567
1568    if (!SystemTimeToFileTime(&ts, &tf)) {
1569        error_setg(errp, "Failed to convert system time: %d", (int)GetLastError());
1570        return -1;
1571    }
1572
1573    return ((((int64_t)tf.dwHighDateTime << 32) | tf.dwLowDateTime)
1574                - W32_FT_OFFSET) * 100;
1575}
1576
1577void qmp_guest_set_time(bool has_time, int64_t time_ns, Error **errp)
1578{
1579    Error *local_err = NULL;
1580    SYSTEMTIME ts;
1581    FILETIME tf;
1582    LONGLONG time;
1583
1584    if (!has_time) {
1585        /* Unfortunately, Windows libraries don't provide an easy way to access
1586         * RTC yet:
1587         *
1588         * https://msdn.microsoft.com/en-us/library/aa908981.aspx
1589         *
1590         * Instead, a workaround is to use the Windows win32tm command to
1591         * resync the time using the Windows Time service.
1592         */
1593        LPVOID msg_buffer;
1594        DWORD ret_flags;
1595
1596        HRESULT hr = system("w32tm /resync /nowait");
1597
1598        if (GetLastError() != 0) {
1599            strerror_s((LPTSTR) & msg_buffer, 0, errno);
1600            error_setg(errp, "system(...) failed: %s", (LPCTSTR)msg_buffer);
1601        } else if (hr != 0) {
1602            if (hr == HRESULT_FROM_WIN32(ERROR_SERVICE_NOT_ACTIVE)) {
1603                error_setg(errp, "Windows Time service not running on the "
1604                                 "guest");
1605            } else {
1606                if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
1607                                   FORMAT_MESSAGE_FROM_SYSTEM |
1608                                   FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
1609                                   (DWORD)hr, MAKELANGID(LANG_NEUTRAL,
1610                                   SUBLANG_DEFAULT), (LPTSTR) & msg_buffer, 0,
1611                                   NULL)) {
1612                    error_setg(errp, "w32tm failed with error (0x%lx), couldn'"
1613                                     "t retrieve error message", hr);
1614                } else {
1615                    error_setg(errp, "w32tm failed with error (0x%lx): %s", hr,
1616                               (LPCTSTR)msg_buffer);
1617                    LocalFree(msg_buffer);
1618                }
1619            }
1620        } else if (!InternetGetConnectedState(&ret_flags, 0)) {
1621            error_setg(errp, "No internet connection on guest, sync not "
1622                             "accurate");
1623        }
1624        return;
1625    }
1626
1627    /* Validate time passed by user. */
1628    if (time_ns < 0 || time_ns / 100 > INT64_MAX - W32_FT_OFFSET) {
1629        error_setg(errp, "Time %" PRId64 "is invalid", time_ns);
1630        return;
1631    }
1632
1633    time = time_ns / 100 + W32_FT_OFFSET;
1634
1635    tf.dwLowDateTime = (DWORD) time;
1636    tf.dwHighDateTime = (DWORD) (time >> 32);
1637
1638    if (!FileTimeToSystemTime(&tf, &ts)) {
1639        error_setg(errp, "Failed to convert system time %d",
1640                   (int)GetLastError());
1641        return;
1642    }
1643
1644    acquire_privilege(SE_SYSTEMTIME_NAME, &local_err);
1645    if (local_err) {
1646        error_propagate(errp, local_err);
1647        return;
1648    }
1649
1650    if (!SetSystemTime(&ts)) {
1651        error_setg(errp, "Failed to set time to guest: %d", (int)GetLastError());
1652        return;
1653    }
1654}
1655
1656GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
1657{
1658    PSYSTEM_LOGICAL_PROCESSOR_INFORMATION pslpi, ptr;
1659    DWORD length;
1660    GuestLogicalProcessorList *head, **link;
1661    Error *local_err = NULL;
1662    int64_t current;
1663
1664    ptr = pslpi = NULL;
1665    length = 0;
1666    current = 0;
1667    head = NULL;
1668    link = &head;
1669
1670    if ((GetLogicalProcessorInformation(pslpi, &length) == FALSE) &&
1671        (GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
1672        (length > sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION))) {
1673        ptr = pslpi = g_malloc0(length);
1674        if (GetLogicalProcessorInformation(pslpi, &length) == FALSE) {
1675            error_setg(&local_err, "Failed to get processor information: %d",
1676                       (int)GetLastError());
1677        }
1678    } else {
1679        error_setg(&local_err,
1680                   "Failed to get processor information buffer length: %d",
1681                   (int)GetLastError());
1682    }
1683
1684    while ((local_err == NULL) && (length > 0)) {
1685        if (pslpi->Relationship == RelationProcessorCore) {
1686            ULONG_PTR cpu_bits = pslpi->ProcessorMask;
1687
1688            while (cpu_bits > 0) {
1689                if (!!(cpu_bits & 1)) {
1690                    GuestLogicalProcessor *vcpu;
1691                    GuestLogicalProcessorList *entry;
1692
1693                    vcpu = g_malloc0(sizeof *vcpu);
1694                    vcpu->logical_id = current++;
1695                    vcpu->online = true;
1696                    vcpu->has_can_offline = true;
1697
1698                    entry = g_malloc0(sizeof *entry);
1699                    entry->value = vcpu;
1700
1701                    *link = entry;
1702                    link = &entry->next;
1703                }
1704                cpu_bits >>= 1;
1705            }
1706        }
1707        length -= sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
1708        pslpi++; /* next entry */
1709    }
1710
1711    g_free(ptr);
1712
1713    if (local_err == NULL) {
1714        if (head != NULL) {
1715            return head;
1716        }
1717        /* there's no guest with zero VCPUs */
1718        error_setg(&local_err, "Guest reported zero VCPUs");
1719    }
1720
1721    qapi_free_GuestLogicalProcessorList(head);
1722    error_propagate(errp, local_err);
1723    return NULL;
1724}
1725
1726int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
1727{
1728    error_setg(errp, QERR_UNSUPPORTED);
1729    return -1;
1730}
1731
1732static gchar *
1733get_net_error_message(gint error)
1734{
1735    HMODULE module = NULL;
1736    gchar *retval = NULL;
1737    wchar_t *msg = NULL;
1738    int flags;
1739    size_t nchars;
1740
1741    flags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
1742        FORMAT_MESSAGE_IGNORE_INSERTS |
1743        FORMAT_MESSAGE_FROM_SYSTEM;
1744
1745    if (error >= NERR_BASE && error <= MAX_NERR) {
1746        module = LoadLibraryExW(L"netmsg.dll", NULL, LOAD_LIBRARY_AS_DATAFILE);
1747
1748        if (module != NULL) {
1749            flags |= FORMAT_MESSAGE_FROM_HMODULE;
1750        }
1751    }
1752
1753    FormatMessageW(flags, module, error, 0, (LPWSTR)&msg, 0, NULL);
1754
1755    if (msg != NULL) {
1756        nchars = wcslen(msg);
1757
1758        if (nchars >= 2 &&
1759            msg[nchars - 1] == L'\n' &&
1760            msg[nchars - 2] == L'\r') {
1761            msg[nchars - 2] = L'\0';
1762        }
1763
1764        retval = g_utf16_to_utf8(msg, -1, NULL, NULL, NULL);
1765
1766        LocalFree(msg);
1767    }
1768
1769    if (module != NULL) {
1770        FreeLibrary(module);
1771    }
1772
1773    return retval;
1774}
1775
1776void qmp_guest_set_user_password(const char *username,
1777                                 const char *password,
1778                                 bool crypted,
1779                                 Error **errp)
1780{
1781    NET_API_STATUS nas;
1782    char *rawpasswddata = NULL;
1783    size_t rawpasswdlen;
1784    wchar_t *user = NULL, *wpass = NULL;
1785    USER_INFO_1003 pi1003 = { 0, };
1786    GError *gerr = NULL;
1787
1788    if (crypted) {
1789        error_setg(errp, QERR_UNSUPPORTED);
1790        return;
1791    }
1792
1793    rawpasswddata = (char *)qbase64_decode(password, -1, &rawpasswdlen, errp);
1794    if (!rawpasswddata) {
1795        return;
1796    }
1797    rawpasswddata = g_renew(char, rawpasswddata, rawpasswdlen + 1);
1798    rawpasswddata[rawpasswdlen] = '\0';
1799
1800    user = g_utf8_to_utf16(username, -1, NULL, NULL, &gerr);
1801    if (!user) {
1802        goto done;
1803    }
1804
1805    wpass = g_utf8_to_utf16(rawpasswddata, -1, NULL, NULL, &gerr);
1806    if (!wpass) {
1807        goto done;
1808    }
1809
1810    pi1003.usri1003_password = wpass;
1811    nas = NetUserSetInfo(NULL, user,
1812                         1003, (LPBYTE)&pi1003,
1813                         NULL);
1814
1815    if (nas != NERR_Success) {
1816        gchar *msg = get_net_error_message(nas);
1817        error_setg(errp, "failed to set password: %s", msg);
1818        g_free(msg);
1819    }
1820
1821done:
1822    if (gerr) {
1823        error_setg(errp, QERR_QGA_COMMAND_FAILED, gerr->message);
1824        g_error_free(gerr);
1825    }
1826    g_free(user);
1827    g_free(wpass);
1828    g_free(rawpasswddata);
1829}
1830
1831GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp)
1832{
1833    error_setg(errp, QERR_UNSUPPORTED);
1834    return NULL;
1835}
1836
1837GuestMemoryBlockResponseList *
1838qmp_guest_set_memory_blocks(GuestMemoryBlockList *mem_blks, Error **errp)
1839{
1840    error_setg(errp, QERR_UNSUPPORTED);
1841    return NULL;
1842}
1843
1844GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp)
1845{
1846    error_setg(errp, QERR_UNSUPPORTED);
1847    return NULL;
1848}
1849
1850/* add unsupported commands to the blacklist */
1851GList *ga_command_blacklist_init(GList *blacklist)
1852{
1853    const char *list_unsupported[] = {
1854        "guest-suspend-hybrid",
1855        "guest-set-vcpus",
1856        "guest-get-memory-blocks", "guest-set-memory-blocks",
1857        "guest-get-memory-block-size",
1858        NULL};
1859    char **p = (char **)list_unsupported;
1860
1861    while (*p) {
1862        blacklist = g_list_append(blacklist, g_strdup(*p++));
1863    }
1864
1865    if (!vss_init(true)) {
1866        g_debug("vss_init failed, vss commands are going to be disabled");
1867        const char *list[] = {
1868            "guest-get-fsinfo", "guest-fsfreeze-status",
1869            "guest-fsfreeze-freeze", "guest-fsfreeze-thaw", NULL};
1870        p = (char **)list;
1871
1872        while (*p) {
1873            blacklist = g_list_append(blacklist, g_strdup(*p++));
1874        }
1875    }
1876
1877    return blacklist;
1878}
1879
1880/* register init/cleanup routines for stateful command groups */
1881void ga_command_state_init(GAState *s, GACommandState *cs)
1882{
1883    if (!vss_initialized()) {
1884        ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup);
1885    }
1886}
1887
1888/* MINGW is missing two fields: IncomingFrames & OutgoingFrames */
1889typedef struct _GA_WTSINFOA {
1890    WTS_CONNECTSTATE_CLASS State;
1891    DWORD SessionId;
1892    DWORD IncomingBytes;
1893    DWORD OutgoingBytes;
1894    DWORD IncomingFrames;
1895    DWORD OutgoingFrames;
1896    DWORD IncomingCompressedBytes;
1897    DWORD OutgoingCompressedBy;
1898    CHAR WinStationName[WINSTATIONNAME_LENGTH];
1899    CHAR Domain[DOMAIN_LENGTH];
1900    CHAR UserName[USERNAME_LENGTH + 1];
1901    LARGE_INTEGER ConnectTime;
1902    LARGE_INTEGER DisconnectTime;
1903    LARGE_INTEGER LastInputTime;
1904    LARGE_INTEGER LogonTime;
1905    LARGE_INTEGER CurrentTime;
1906
1907} GA_WTSINFOA;
1908
1909GuestUserList *qmp_guest_get_users(Error **err)
1910{
1911#if (_WIN32_WINNT >= 0x0600)
1912#define QGA_NANOSECONDS 10000000
1913
1914    GHashTable *cache = NULL;
1915    GuestUserList *head = NULL, *cur_item = NULL;
1916
1917    DWORD buffer_size = 0, count = 0, i = 0;
1918    GA_WTSINFOA *info = NULL;
1919    WTS_SESSION_INFOA *entries = NULL;
1920    GuestUserList *item = NULL;
1921    GuestUser *user = NULL;
1922    gpointer value = NULL;
1923    INT64 login = 0;
1924    double login_time = 0;
1925
1926    cache = g_hash_table_new(g_str_hash, g_str_equal);
1927
1928    if (WTSEnumerateSessionsA(NULL, 0, 1, &entries, &count)) {
1929        for (i = 0; i < count; ++i) {
1930            buffer_size = 0;
1931            info = NULL;
1932            if (WTSQuerySessionInformationA(
1933                NULL,
1934                entries[i].SessionId,
1935                WTSSessionInfo,
1936                (LPSTR *)&info,
1937                &buffer_size
1938            )) {
1939
1940                if (strlen(info->UserName) == 0) {
1941                    WTSFreeMemory(info);
1942                    continue;
1943                }
1944
1945                login = info->LogonTime.QuadPart;
1946                login -= W32_FT_OFFSET;
1947                login_time = ((double)login) / QGA_NANOSECONDS;
1948
1949                if (g_hash_table_contains(cache, info->UserName)) {
1950                    value = g_hash_table_lookup(cache, info->UserName);
1951                    user = (GuestUser *)value;
1952                    if (user->login_time > login_time) {
1953                        user->login_time = login_time;
1954                    }
1955                } else {
1956                    item = g_new0(GuestUserList, 1);
1957                    item->value = g_new0(GuestUser, 1);
1958
1959                    item->value->user = g_strdup(info->UserName);
1960                    item->value->domain = g_strdup(info->Domain);
1961                    item->value->has_domain = true;
1962
1963                    item->value->login_time = login_time;
1964
1965                    g_hash_table_add(cache, item->value->user);
1966
1967                    if (!cur_item) {
1968                        head = cur_item = item;
1969                    } else {
1970                        cur_item->next = item;
1971                        cur_item = item;
1972                    }
1973                }
1974            }
1975            WTSFreeMemory(info);
1976        }
1977        WTSFreeMemory(entries);
1978    }
1979    g_hash_table_destroy(cache);
1980    return head;
1981#else
1982    error_setg(err, QERR_UNSUPPORTED);
1983    return NULL;
1984#endif
1985}
1986
1987typedef struct _ga_matrix_lookup_t {
1988    int major;
1989    int minor;
1990    char const *version;
1991    char const *version_id;
1992} ga_matrix_lookup_t;
1993
1994static ga_matrix_lookup_t const WIN_VERSION_MATRIX[2][8] = {
1995    {
1996        /* Desktop editions */
1997        { 5, 0, "Microsoft Windows 2000",   "2000"},
1998        { 5, 1, "Microsoft Windows XP",     "xp"},
1999        { 6, 0, "Microsoft Windows Vista",  "vista"},
2000        { 6, 1, "Microsoft Windows 7"       "7"},
2001        { 6, 2, "Microsoft Windows 8",      "8"},
2002        { 6, 3, "Microsoft Windows 8.1",    "8.1"},
2003        {10, 0, "Microsoft Windows 10",     "10"},
2004        { 0, 0, 0}
2005    },{
2006        /* Server editions */
2007        { 5, 2, "Microsoft Windows Server 2003",        "2003"},
2008        { 6, 0, "Microsoft Windows Server 2008",        "2008"},
2009        { 6, 1, "Microsoft Windows Server 2008 R2",     "2008r2"},
2010        { 6, 2, "Microsoft Windows Server 2012",        "2012"},
2011        { 6, 3, "Microsoft Windows Server 2012 R2",     "2012r2"},
2012        {10, 0, "Microsoft Windows Server 2016",        "2016"},
2013        { 0, 0, 0},
2014        { 0, 0, 0}
2015    }
2016};
2017
2018static void ga_get_win_version(RTL_OSVERSIONINFOEXW *info, Error **errp)
2019{
2020    typedef NTSTATUS(WINAPI * rtl_get_version_t)(
2021        RTL_OSVERSIONINFOEXW *os_version_info_ex);
2022
2023    info->dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
2024
2025    HMODULE module = GetModuleHandle("ntdll");
2026    PVOID fun = GetProcAddress(module, "RtlGetVersion");
2027    if (fun == NULL) {
2028        error_setg(errp, QERR_QGA_COMMAND_FAILED,
2029            "Failed to get address of RtlGetVersion");
2030        return;
2031    }
2032
2033    rtl_get_version_t rtl_get_version = (rtl_get_version_t)fun;
2034    rtl_get_version(info);
2035    return;
2036}
2037
2038static char *ga_get_win_name(OSVERSIONINFOEXW const *os_version, bool id)
2039{
2040    DWORD major = os_version->dwMajorVersion;
2041    DWORD minor = os_version->dwMinorVersion;
2042    int tbl_idx = (os_version->wProductType != VER_NT_WORKSTATION);
2043    ga_matrix_lookup_t const *table = WIN_VERSION_MATRIX[tbl_idx];
2044    while (table->version != NULL) {
2045        if (major == table->major && minor == table->minor) {
2046            if (id) {
2047                return g_strdup(table->version_id);
2048            } else {
2049                return g_strdup(table->version);
2050            }
2051        }
2052        ++table;
2053    }
2054    slog("failed to lookup Windows version: major=%lu, minor=%lu",
2055        major, minor);
2056    return g_strdup("N/A");
2057}
2058
2059static char *ga_get_win_product_name(Error **errp)
2060{
2061    HKEY key = NULL;
2062    DWORD size = 128;
2063    char *result = g_malloc0(size);
2064    LONG err = ERROR_SUCCESS;
2065
2066    err = RegOpenKeyA(HKEY_LOCAL_MACHINE,
2067                      "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
2068                      &key);
2069    if (err != ERROR_SUCCESS) {
2070        error_setg_win32(errp, err, "failed to open registry key");
2071        goto fail;
2072    }
2073
2074    err = RegQueryValueExA(key, "ProductName", NULL, NULL,
2075                            (LPBYTE)result, &size);
2076    if (err == ERROR_MORE_DATA) {
2077        slog("ProductName longer than expected (%lu bytes), retrying",
2078                size);
2079        g_free(result);
2080        result = NULL;
2081        if (size > 0) {
2082            result = g_malloc0(size);
2083            err = RegQueryValueExA(key, "ProductName", NULL, NULL,
2084                                    (LPBYTE)result, &size);
2085        }
2086    }
2087    if (err != ERROR_SUCCESS) {
2088        error_setg_win32(errp, err, "failed to retrive ProductName");
2089        goto fail;
2090    }
2091
2092    return result;
2093
2094fail:
2095    g_free(result);
2096    return NULL;
2097}
2098
2099static char *ga_get_current_arch(void)
2100{
2101    SYSTEM_INFO info;
2102    GetNativeSystemInfo(&info);
2103    char *result = NULL;
2104    switch (info.wProcessorArchitecture) {
2105    case PROCESSOR_ARCHITECTURE_AMD64:
2106        result = g_strdup("x86_64");
2107        break;
2108    case PROCESSOR_ARCHITECTURE_ARM:
2109        result = g_strdup("arm");
2110        break;
2111    case PROCESSOR_ARCHITECTURE_IA64:
2112        result = g_strdup("ia64");
2113        break;
2114    case PROCESSOR_ARCHITECTURE_INTEL:
2115        result = g_strdup("x86");
2116        break;
2117    case PROCESSOR_ARCHITECTURE_UNKNOWN:
2118    default:
2119        slog("unknown processor architecture 0x%0x",
2120            info.wProcessorArchitecture);
2121        result = g_strdup("unknown");
2122        break;
2123    }
2124    return result;
2125}
2126
2127GuestOSInfo *qmp_guest_get_osinfo(Error **errp)
2128{
2129    Error *local_err = NULL;
2130    OSVERSIONINFOEXW os_version = {0};
2131    bool server;
2132    char *product_name;
2133    GuestOSInfo *info;
2134
2135    ga_get_win_version(&os_version, &local_err);
2136    if (local_err) {
2137        error_propagate(errp, local_err);
2138        return NULL;
2139    }
2140
2141    server = os_version.wProductType != VER_NT_WORKSTATION;
2142    product_name = ga_get_win_product_name(&local_err);
2143    if (product_name == NULL) {
2144        error_propagate(errp, local_err);
2145        return NULL;
2146    }
2147
2148    info = g_new0(GuestOSInfo, 1);
2149
2150    info->has_kernel_version = true;
2151    info->kernel_version = g_strdup_printf("%lu.%lu",
2152        os_version.dwMajorVersion,
2153        os_version.dwMinorVersion);
2154    info->has_kernel_release = true;
2155    info->kernel_release = g_strdup_printf("%lu",
2156        os_version.dwBuildNumber);
2157    info->has_machine = true;
2158    info->machine = ga_get_current_arch();
2159
2160    info->has_id = true;
2161    info->id = g_strdup("mswindows");
2162    info->has_name = true;
2163    info->name = g_strdup("Microsoft Windows");
2164    info->has_pretty_name = true;
2165    info->pretty_name = product_name;
2166    info->has_version = true;
2167    info->version = ga_get_win_name(&os_version, false);
2168    info->has_version_id = true;
2169    info->version_id = ga_get_win_name(&os_version, true);
2170    info->has_variant = true;
2171    info->variant = g_strdup(server ? "server" : "client");
2172    info->has_variant_id = true;
2173    info->variant_id = g_strdup(server ? "server" : "client");
2174
2175    return info;
2176}
2177