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