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 #include <glib.h> 15 #include <wtypes.h> 16 #include <powrprof.h> 17 #include <stdio.h> 18 #include <string.h> 19 #include <winsock2.h> 20 #include <ws2tcpip.h> 21 #include <iptypes.h> 22 #include <iphlpapi.h> 23 #ifdef CONFIG_QGA_NTDDSCSI 24 #include <winioctl.h> 25 #include <ntddscsi.h> 26 #include <setupapi.h> 27 #include <initguid.h> 28 #endif 29 #include "qga/guest-agent-core.h" 30 #include "qga/vss-win32.h" 31 #include "qga-qmp-commands.h" 32 #include "qapi/qmp/qerror.h" 33 #include "qemu/queue.h" 34 #include "qemu/host-utils.h" 35 36 #ifndef SHTDN_REASON_FLAG_PLANNED 37 #define SHTDN_REASON_FLAG_PLANNED 0x80000000 38 #endif 39 40 /* multiple of 100 nanoseconds elapsed between windows baseline 41 * (1/1/1601) and Unix Epoch (1/1/1970), accounting for leap years */ 42 #define W32_FT_OFFSET (10000000ULL * 60 * 60 * 24 * \ 43 (365 * (1970 - 1601) + \ 44 (1970 - 1601) / 4 - 3)) 45 46 #define INVALID_SET_FILE_POINTER ((DWORD)-1) 47 48 typedef struct GuestFileHandle { 49 int64_t id; 50 HANDLE fh; 51 QTAILQ_ENTRY(GuestFileHandle) next; 52 } GuestFileHandle; 53 54 static struct { 55 QTAILQ_HEAD(, GuestFileHandle) filehandles; 56 } guest_file_state; 57 58 59 typedef struct OpenFlags { 60 const char *forms; 61 DWORD desired_access; 62 DWORD creation_disposition; 63 } OpenFlags; 64 static OpenFlags guest_file_open_modes[] = { 65 {"r", GENERIC_READ, OPEN_EXISTING}, 66 {"rb", GENERIC_READ, OPEN_EXISTING}, 67 {"w", GENERIC_WRITE, CREATE_ALWAYS}, 68 {"wb", GENERIC_WRITE, CREATE_ALWAYS}, 69 {"a", GENERIC_WRITE, OPEN_ALWAYS }, 70 {"r+", GENERIC_WRITE|GENERIC_READ, OPEN_EXISTING}, 71 {"rb+", GENERIC_WRITE|GENERIC_READ, OPEN_EXISTING}, 72 {"r+b", GENERIC_WRITE|GENERIC_READ, OPEN_EXISTING}, 73 {"w+", GENERIC_WRITE|GENERIC_READ, CREATE_ALWAYS}, 74 {"wb+", GENERIC_WRITE|GENERIC_READ, CREATE_ALWAYS}, 75 {"w+b", GENERIC_WRITE|GENERIC_READ, CREATE_ALWAYS}, 76 {"a+", GENERIC_WRITE|GENERIC_READ, OPEN_ALWAYS }, 77 {"ab+", GENERIC_WRITE|GENERIC_READ, OPEN_ALWAYS }, 78 {"a+b", GENERIC_WRITE|GENERIC_READ, OPEN_ALWAYS } 79 }; 80 81 static OpenFlags *find_open_flag(const char *mode_str) 82 { 83 int mode; 84 Error **errp = NULL; 85 86 for (mode = 0; mode < ARRAY_SIZE(guest_file_open_modes); ++mode) { 87 OpenFlags *flags = guest_file_open_modes + mode; 88 89 if (strcmp(flags->forms, mode_str) == 0) { 90 return flags; 91 } 92 } 93 94 error_setg(errp, "invalid file open mode '%s'", mode_str); 95 return NULL; 96 } 97 98 static int64_t guest_file_handle_add(HANDLE fh, Error **errp) 99 { 100 GuestFileHandle *gfh; 101 int64_t handle; 102 103 handle = ga_get_fd_handle(ga_state, errp); 104 if (handle < 0) { 105 return -1; 106 } 107 gfh = g_malloc0(sizeof(GuestFileHandle)); 108 gfh->id = handle; 109 gfh->fh = fh; 110 QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next); 111 112 return handle; 113 } 114 115 static GuestFileHandle *guest_file_handle_find(int64_t id, Error **errp) 116 { 117 GuestFileHandle *gfh; 118 QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next) { 119 if (gfh->id == id) { 120 return gfh; 121 } 122 } 123 error_setg(errp, "handle '%" PRId64 "' has not been found", id); 124 return NULL; 125 } 126 127 int64_t qmp_guest_file_open(const char *path, bool has_mode, 128 const char *mode, Error **errp) 129 { 130 int64_t fd; 131 HANDLE fh; 132 HANDLE templ_file = NULL; 133 DWORD share_mode = FILE_SHARE_READ; 134 DWORD flags_and_attr = FILE_ATTRIBUTE_NORMAL; 135 LPSECURITY_ATTRIBUTES sa_attr = NULL; 136 OpenFlags *guest_flags; 137 138 if (!has_mode) { 139 mode = "r"; 140 } 141 slog("guest-file-open called, filepath: %s, mode: %s", path, mode); 142 guest_flags = find_open_flag(mode); 143 if (guest_flags == NULL) { 144 error_setg(errp, "invalid file open mode"); 145 return -1; 146 } 147 148 fh = CreateFile(path, guest_flags->desired_access, share_mode, sa_attr, 149 guest_flags->creation_disposition, flags_and_attr, 150 templ_file); 151 if (fh == INVALID_HANDLE_VALUE) { 152 error_setg_win32(errp, GetLastError(), "failed to open file '%s'", 153 path); 154 return -1; 155 } 156 157 fd = guest_file_handle_add(fh, errp); 158 if (fd < 0) { 159 CloseHandle(&fh); 160 error_setg(errp, "failed to add handle to qmp handle table"); 161 return -1; 162 } 163 164 slog("guest-file-open, handle: % " PRId64, fd); 165 return fd; 166 } 167 168 void qmp_guest_file_close(int64_t handle, Error **errp) 169 { 170 bool ret; 171 GuestFileHandle *gfh = guest_file_handle_find(handle, errp); 172 slog("guest-file-close called, handle: %" PRId64, handle); 173 if (gfh == NULL) { 174 return; 175 } 176 ret = CloseHandle(gfh->fh); 177 if (!ret) { 178 error_setg_win32(errp, GetLastError(), "failed close handle"); 179 return; 180 } 181 182 QTAILQ_REMOVE(&guest_file_state.filehandles, gfh, next); 183 g_free(gfh); 184 } 185 186 static void acquire_privilege(const char *name, Error **errp) 187 { 188 HANDLE token = NULL; 189 TOKEN_PRIVILEGES priv; 190 Error *local_err = NULL; 191 192 if (OpenProcessToken(GetCurrentProcess(), 193 TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &token)) 194 { 195 if (!LookupPrivilegeValue(NULL, name, &priv.Privileges[0].Luid)) { 196 error_setg(&local_err, QERR_QGA_COMMAND_FAILED, 197 "no luid for requested privilege"); 198 goto out; 199 } 200 201 priv.PrivilegeCount = 1; 202 priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 203 204 if (!AdjustTokenPrivileges(token, FALSE, &priv, 0, NULL, 0)) { 205 error_setg(&local_err, QERR_QGA_COMMAND_FAILED, 206 "unable to acquire requested privilege"); 207 goto out; 208 } 209 210 } else { 211 error_setg(&local_err, QERR_QGA_COMMAND_FAILED, 212 "failed to open privilege token"); 213 } 214 215 out: 216 if (token) { 217 CloseHandle(token); 218 } 219 if (local_err) { 220 error_propagate(errp, local_err); 221 } 222 } 223 224 static void execute_async(DWORD WINAPI (*func)(LPVOID), LPVOID opaque, 225 Error **errp) 226 { 227 Error *local_err = NULL; 228 229 HANDLE thread = CreateThread(NULL, 0, func, opaque, 0, NULL); 230 if (!thread) { 231 error_setg(&local_err, QERR_QGA_COMMAND_FAILED, 232 "failed to dispatch asynchronous command"); 233 error_propagate(errp, local_err); 234 } 235 } 236 237 void qmp_guest_shutdown(bool has_mode, const char *mode, Error **errp) 238 { 239 Error *local_err = NULL; 240 UINT shutdown_flag = EWX_FORCE; 241 242 slog("guest-shutdown called, mode: %s", mode); 243 244 if (!has_mode || strcmp(mode, "powerdown") == 0) { 245 shutdown_flag |= EWX_POWEROFF; 246 } else if (strcmp(mode, "halt") == 0) { 247 shutdown_flag |= EWX_SHUTDOWN; 248 } else if (strcmp(mode, "reboot") == 0) { 249 shutdown_flag |= EWX_REBOOT; 250 } else { 251 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "mode", 252 "halt|powerdown|reboot"); 253 return; 254 } 255 256 /* Request a shutdown privilege, but try to shut down the system 257 anyway. */ 258 acquire_privilege(SE_SHUTDOWN_NAME, &local_err); 259 if (local_err) { 260 error_propagate(errp, local_err); 261 return; 262 } 263 264 if (!ExitWindowsEx(shutdown_flag, SHTDN_REASON_FLAG_PLANNED)) { 265 slog("guest-shutdown failed: %lu", GetLastError()); 266 error_setg(errp, QERR_UNDEFINED_ERROR); 267 } 268 } 269 270 GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count, 271 int64_t count, Error **errp) 272 { 273 GuestFileRead *read_data = NULL; 274 guchar *buf; 275 HANDLE fh; 276 bool is_ok; 277 DWORD read_count; 278 GuestFileHandle *gfh = guest_file_handle_find(handle, errp); 279 280 if (!gfh) { 281 return NULL; 282 } 283 if (!has_count) { 284 count = QGA_READ_COUNT_DEFAULT; 285 } else if (count < 0) { 286 error_setg(errp, "value '%" PRId64 287 "' is invalid for argument count", count); 288 return NULL; 289 } 290 291 fh = gfh->fh; 292 buf = g_malloc0(count+1); 293 is_ok = ReadFile(fh, buf, count, &read_count, NULL); 294 if (!is_ok) { 295 error_setg_win32(errp, GetLastError(), "failed to read file"); 296 slog("guest-file-read failed, handle %" PRId64, handle); 297 } else { 298 buf[read_count] = 0; 299 read_data = g_malloc0(sizeof(GuestFileRead)); 300 read_data->count = (size_t)read_count; 301 read_data->eof = read_count == 0; 302 303 if (read_count != 0) { 304 read_data->buf_b64 = g_base64_encode(buf, read_count); 305 } 306 } 307 g_free(buf); 308 309 return read_data; 310 } 311 312 GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64, 313 bool has_count, int64_t count, 314 Error **errp) 315 { 316 GuestFileWrite *write_data = NULL; 317 guchar *buf; 318 gsize buf_len; 319 bool is_ok; 320 DWORD write_count; 321 GuestFileHandle *gfh = guest_file_handle_find(handle, errp); 322 HANDLE fh; 323 324 if (!gfh) { 325 return NULL; 326 } 327 fh = gfh->fh; 328 buf = g_base64_decode(buf_b64, &buf_len); 329 330 if (!has_count) { 331 count = buf_len; 332 } else if (count < 0 || count > buf_len) { 333 error_setg(errp, "value '%" PRId64 334 "' is invalid for argument count", count); 335 goto done; 336 } 337 338 is_ok = WriteFile(fh, buf, count, &write_count, NULL); 339 if (!is_ok) { 340 error_setg_win32(errp, GetLastError(), "failed to write to file"); 341 slog("guest-file-write-failed, handle: %" PRId64, handle); 342 } else { 343 write_data = g_malloc0(sizeof(GuestFileWrite)); 344 write_data->count = (size_t) write_count; 345 } 346 347 done: 348 g_free(buf); 349 return write_data; 350 } 351 352 GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset, 353 int64_t whence, Error **errp) 354 { 355 GuestFileHandle *gfh; 356 GuestFileSeek *seek_data; 357 HANDLE fh; 358 LARGE_INTEGER new_pos, off_pos; 359 off_pos.QuadPart = offset; 360 BOOL res; 361 gfh = guest_file_handle_find(handle, errp); 362 if (!gfh) { 363 return NULL; 364 } 365 366 fh = gfh->fh; 367 res = SetFilePointerEx(fh, off_pos, &new_pos, whence); 368 if (!res) { 369 error_setg_win32(errp, GetLastError(), "failed to seek file"); 370 return NULL; 371 } 372 seek_data = g_new0(GuestFileSeek, 1); 373 seek_data->position = new_pos.QuadPart; 374 return seek_data; 375 } 376 377 void qmp_guest_file_flush(int64_t handle, Error **errp) 378 { 379 HANDLE fh; 380 GuestFileHandle *gfh = guest_file_handle_find(handle, errp); 381 if (!gfh) { 382 return; 383 } 384 385 fh = gfh->fh; 386 if (!FlushFileBuffers(fh)) { 387 error_setg_win32(errp, GetLastError(), "failed to flush file"); 388 } 389 } 390 391 static void guest_file_init(void) 392 { 393 QTAILQ_INIT(&guest_file_state.filehandles); 394 } 395 396 #ifdef CONFIG_QGA_NTDDSCSI 397 398 static STORAGE_BUS_TYPE win2qemu[] = { 399 [BusTypeUnknown] = GUEST_DISK_BUS_TYPE_UNKNOWN, 400 [BusTypeScsi] = GUEST_DISK_BUS_TYPE_SCSI, 401 [BusTypeAtapi] = GUEST_DISK_BUS_TYPE_IDE, 402 [BusTypeAta] = GUEST_DISK_BUS_TYPE_IDE, 403 [BusType1394] = GUEST_DISK_BUS_TYPE_IEEE1394, 404 [BusTypeSsa] = GUEST_DISK_BUS_TYPE_SSA, 405 [BusTypeFibre] = GUEST_DISK_BUS_TYPE_SSA, 406 [BusTypeUsb] = GUEST_DISK_BUS_TYPE_USB, 407 [BusTypeRAID] = GUEST_DISK_BUS_TYPE_RAID, 408 #if (_WIN32_WINNT >= 0x0600) 409 [BusTypeiScsi] = GUEST_DISK_BUS_TYPE_ISCSI, 410 [BusTypeSas] = GUEST_DISK_BUS_TYPE_SAS, 411 [BusTypeSata] = GUEST_DISK_BUS_TYPE_SATA, 412 [BusTypeSd] = GUEST_DISK_BUS_TYPE_SD, 413 [BusTypeMmc] = GUEST_DISK_BUS_TYPE_MMC, 414 #endif 415 #if (_WIN32_WINNT >= 0x0601) 416 [BusTypeVirtual] = GUEST_DISK_BUS_TYPE_VIRTUAL, 417 [BusTypeFileBackedVirtual] = GUEST_DISK_BUS_TYPE_FILE_BACKED_VIRTUAL, 418 #endif 419 }; 420 421 static GuestDiskBusType find_bus_type(STORAGE_BUS_TYPE bus) 422 { 423 if (bus > ARRAY_SIZE(win2qemu) || (int)bus < 0) { 424 return GUEST_DISK_BUS_TYPE_UNKNOWN; 425 } 426 return win2qemu[(int)bus]; 427 } 428 429 DEFINE_GUID(GUID_DEVINTERFACE_VOLUME, 430 0x53f5630dL, 0xb6bf, 0x11d0, 0x94, 0xf2, 431 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); 432 433 static GuestPCIAddress *get_pci_info(char *guid, Error **errp) 434 { 435 HDEVINFO dev_info; 436 SP_DEVINFO_DATA dev_info_data; 437 DWORD size = 0; 438 int i; 439 char dev_name[MAX_PATH]; 440 char *buffer = NULL; 441 GuestPCIAddress *pci = NULL; 442 char *name = g_strdup(&guid[4]); 443 444 if (!QueryDosDevice(name, dev_name, ARRAY_SIZE(dev_name))) { 445 error_setg_win32(errp, GetLastError(), "failed to get dos device name"); 446 goto out; 447 } 448 449 dev_info = SetupDiGetClassDevs(&GUID_DEVINTERFACE_VOLUME, 0, 0, 450 DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); 451 if (dev_info == INVALID_HANDLE_VALUE) { 452 error_setg_win32(errp, GetLastError(), "failed to get devices tree"); 453 goto out; 454 } 455 456 dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA); 457 for (i = 0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) { 458 DWORD addr, bus, slot, func, dev, data, size2; 459 while (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, 460 SPDRP_PHYSICAL_DEVICE_OBJECT_NAME, 461 &data, (PBYTE)buffer, size, 462 &size2)) { 463 size = MAX(size, size2); 464 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { 465 g_free(buffer); 466 /* Double the size to avoid problems on 467 * W2k MBCS systems per KB 888609. 468 * https://support.microsoft.com/en-us/kb/259695 */ 469 buffer = g_malloc(size * 2); 470 } else { 471 error_setg_win32(errp, GetLastError(), 472 "failed to get device name"); 473 goto out; 474 } 475 } 476 477 if (g_strcmp0(buffer, dev_name)) { 478 continue; 479 } 480 481 /* There is no need to allocate buffer in the next functions. The size 482 * is known and ULONG according to 483 * https://support.microsoft.com/en-us/kb/253232 484 * https://msdn.microsoft.com/en-us/library/windows/hardware/ff543095(v=vs.85).aspx 485 */ 486 if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, 487 SPDRP_BUSNUMBER, &data, (PBYTE)&bus, size, NULL)) { 488 break; 489 } 490 491 /* The function retrieves the device's address. This value will be 492 * transformed into device function and number */ 493 if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, 494 SPDRP_ADDRESS, &data, (PBYTE)&addr, size, NULL)) { 495 break; 496 } 497 498 /* This call returns UINumber of DEVICE_CAPABILITIES structure. 499 * This number is typically a user-perceived slot number. */ 500 if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, 501 SPDRP_UI_NUMBER, &data, (PBYTE)&slot, size, NULL)) { 502 break; 503 } 504 505 /* SetupApi gives us the same information as driver with 506 * IoGetDeviceProperty. According to Microsoft 507 * https://support.microsoft.com/en-us/kb/253232 508 * FunctionNumber = (USHORT)((propertyAddress) & 0x0000FFFF); 509 * DeviceNumber = (USHORT)(((propertyAddress) >> 16) & 0x0000FFFF); 510 * SPDRP_ADDRESS is propertyAddress, so we do the same.*/ 511 512 func = addr & 0x0000FFFF; 513 dev = (addr >> 16) & 0x0000FFFF; 514 pci = g_malloc0(sizeof(*pci)); 515 pci->domain = dev; 516 pci->slot = slot; 517 pci->function = func; 518 pci->bus = bus; 519 break; 520 } 521 out: 522 g_free(buffer); 523 g_free(name); 524 return pci; 525 } 526 527 static int get_disk_bus_type(HANDLE vol_h, Error **errp) 528 { 529 STORAGE_PROPERTY_QUERY query; 530 STORAGE_DEVICE_DESCRIPTOR *dev_desc, buf; 531 DWORD received; 532 533 dev_desc = &buf; 534 dev_desc->Size = sizeof(buf); 535 query.PropertyId = StorageDeviceProperty; 536 query.QueryType = PropertyStandardQuery; 537 538 if (!DeviceIoControl(vol_h, IOCTL_STORAGE_QUERY_PROPERTY, &query, 539 sizeof(STORAGE_PROPERTY_QUERY), dev_desc, 540 dev_desc->Size, &received, NULL)) { 541 error_setg_win32(errp, GetLastError(), "failed to get bus type"); 542 return -1; 543 } 544 545 return dev_desc->BusType; 546 } 547 548 /* VSS provider works with volumes, thus there is no difference if 549 * the volume consist of spanned disks. Info about the first disk in the 550 * volume is returned for the spanned disk group (LVM) */ 551 static GuestDiskAddressList *build_guest_disk_info(char *guid, Error **errp) 552 { 553 GuestDiskAddressList *list = NULL; 554 GuestDiskAddress *disk; 555 SCSI_ADDRESS addr, *scsi_ad; 556 DWORD len; 557 int bus; 558 HANDLE vol_h; 559 560 scsi_ad = &addr; 561 char *name = g_strndup(guid, strlen(guid)-1); 562 563 vol_h = CreateFile(name, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, 564 0, NULL); 565 if (vol_h == INVALID_HANDLE_VALUE) { 566 error_setg_win32(errp, GetLastError(), "failed to open volume"); 567 goto out_free; 568 } 569 570 bus = get_disk_bus_type(vol_h, errp); 571 if (bus < 0) { 572 goto out_close; 573 } 574 575 disk = g_malloc0(sizeof(*disk)); 576 disk->bus_type = find_bus_type(bus); 577 if (bus == BusTypeScsi || bus == BusTypeAta || bus == BusTypeRAID 578 #if (_WIN32_WINNT >= 0x0600) 579 /* This bus type is not supported before Windows Server 2003 SP1 */ 580 || bus == BusTypeSas 581 #endif 582 ) { 583 /* We are able to use the same ioctls for different bus types 584 * according to Microsoft docs 585 * https://technet.microsoft.com/en-us/library/ee851589(v=ws.10).aspx */ 586 if (DeviceIoControl(vol_h, IOCTL_SCSI_GET_ADDRESS, NULL, 0, scsi_ad, 587 sizeof(SCSI_ADDRESS), &len, NULL)) { 588 disk->unit = addr.Lun; 589 disk->target = addr.TargetId; 590 disk->bus = addr.PathId; 591 disk->pci_controller = get_pci_info(name, errp); 592 } 593 /* We do not set error in this case, because we still have enough 594 * information about volume. */ 595 } else { 596 disk->pci_controller = NULL; 597 } 598 599 list = g_malloc0(sizeof(*list)); 600 list->value = disk; 601 list->next = NULL; 602 out_close: 603 CloseHandle(vol_h); 604 out_free: 605 g_free(name); 606 return list; 607 } 608 609 #else 610 611 static GuestDiskAddressList *build_guest_disk_info(char *guid, Error **errp) 612 { 613 return NULL; 614 } 615 616 #endif /* CONFIG_QGA_NTDDSCSI */ 617 618 static GuestFilesystemInfo *build_guest_fsinfo(char *guid, Error **errp) 619 { 620 DWORD info_size; 621 char mnt, *mnt_point; 622 char fs_name[32]; 623 char vol_info[MAX_PATH+1]; 624 size_t len; 625 GuestFilesystemInfo *fs = NULL; 626 627 GetVolumePathNamesForVolumeName(guid, (LPCH)&mnt, 0, &info_size); 628 if (GetLastError() != ERROR_MORE_DATA) { 629 error_setg_win32(errp, GetLastError(), "failed to get volume name"); 630 return NULL; 631 } 632 633 mnt_point = g_malloc(info_size + 1); 634 if (!GetVolumePathNamesForVolumeName(guid, mnt_point, info_size, 635 &info_size)) { 636 error_setg_win32(errp, GetLastError(), "failed to get volume name"); 637 goto free; 638 } 639 640 len = strlen(mnt_point); 641 mnt_point[len] = '\\'; 642 mnt_point[len+1] = 0; 643 if (!GetVolumeInformation(mnt_point, vol_info, sizeof(vol_info), NULL, NULL, 644 NULL, (LPSTR)&fs_name, sizeof(fs_name))) { 645 if (GetLastError() != ERROR_NOT_READY) { 646 error_setg_win32(errp, GetLastError(), "failed to get volume info"); 647 } 648 goto free; 649 } 650 651 fs_name[sizeof(fs_name) - 1] = 0; 652 fs = g_malloc(sizeof(*fs)); 653 fs->name = g_strdup(guid); 654 if (len == 0) { 655 fs->mountpoint = g_strdup("System Reserved"); 656 } else { 657 fs->mountpoint = g_strndup(mnt_point, len); 658 } 659 fs->type = g_strdup(fs_name); 660 fs->disk = build_guest_disk_info(guid, errp);; 661 free: 662 g_free(mnt_point); 663 return fs; 664 } 665 666 GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp) 667 { 668 HANDLE vol_h; 669 GuestFilesystemInfoList *new, *ret = NULL; 670 char guid[256]; 671 672 vol_h = FindFirstVolume(guid, sizeof(guid)); 673 if (vol_h == INVALID_HANDLE_VALUE) { 674 error_setg_win32(errp, GetLastError(), "failed to find any volume"); 675 return NULL; 676 } 677 678 do { 679 GuestFilesystemInfo *info = build_guest_fsinfo(guid, errp); 680 if (info == NULL) { 681 continue; 682 } 683 new = g_malloc(sizeof(*ret)); 684 new->value = info; 685 new->next = ret; 686 ret = new; 687 } while (FindNextVolume(vol_h, guid, sizeof(guid))); 688 689 if (GetLastError() != ERROR_NO_MORE_FILES) { 690 error_setg_win32(errp, GetLastError(), "failed to find next volume"); 691 } 692 693 FindVolumeClose(vol_h); 694 return ret; 695 } 696 697 /* 698 * Return status of freeze/thaw 699 */ 700 GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp) 701 { 702 if (!vss_initialized()) { 703 error_setg(errp, QERR_UNSUPPORTED); 704 return 0; 705 } 706 707 if (ga_is_frozen(ga_state)) { 708 return GUEST_FSFREEZE_STATUS_FROZEN; 709 } 710 711 return GUEST_FSFREEZE_STATUS_THAWED; 712 } 713 714 /* 715 * Freeze local file systems using Volume Shadow-copy Service. 716 * The frozen state is limited for up to 10 seconds by VSS. 717 */ 718 int64_t qmp_guest_fsfreeze_freeze(Error **errp) 719 { 720 int i; 721 Error *local_err = NULL; 722 723 if (!vss_initialized()) { 724 error_setg(errp, QERR_UNSUPPORTED); 725 return 0; 726 } 727 728 slog("guest-fsfreeze called"); 729 730 /* cannot risk guest agent blocking itself on a write in this state */ 731 ga_set_frozen(ga_state); 732 733 qga_vss_fsfreeze(&i, &local_err, true); 734 if (local_err) { 735 error_propagate(errp, local_err); 736 goto error; 737 } 738 739 return i; 740 741 error: 742 local_err = NULL; 743 qmp_guest_fsfreeze_thaw(&local_err); 744 if (local_err) { 745 g_debug("cleanup thaw: %s", error_get_pretty(local_err)); 746 error_free(local_err); 747 } 748 return 0; 749 } 750 751 int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints, 752 strList *mountpoints, 753 Error **errp) 754 { 755 error_setg(errp, QERR_UNSUPPORTED); 756 757 return 0; 758 } 759 760 /* 761 * Thaw local file systems using Volume Shadow-copy Service. 762 */ 763 int64_t qmp_guest_fsfreeze_thaw(Error **errp) 764 { 765 int i; 766 767 if (!vss_initialized()) { 768 error_setg(errp, QERR_UNSUPPORTED); 769 return 0; 770 } 771 772 qga_vss_fsfreeze(&i, errp, false); 773 774 ga_unset_frozen(ga_state); 775 return i; 776 } 777 778 static void guest_fsfreeze_cleanup(void) 779 { 780 Error *err = NULL; 781 782 if (!vss_initialized()) { 783 return; 784 } 785 786 if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) { 787 qmp_guest_fsfreeze_thaw(&err); 788 if (err) { 789 slog("failed to clean up frozen filesystems: %s", 790 error_get_pretty(err)); 791 error_free(err); 792 } 793 } 794 795 vss_deinit(true); 796 } 797 798 /* 799 * Walk list of mounted file systems in the guest, and discard unused 800 * areas. 801 */ 802 GuestFilesystemTrimResponse * 803 qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp) 804 { 805 error_setg(errp, QERR_UNSUPPORTED); 806 return NULL; 807 } 808 809 typedef enum { 810 GUEST_SUSPEND_MODE_DISK, 811 GUEST_SUSPEND_MODE_RAM 812 } GuestSuspendMode; 813 814 static void check_suspend_mode(GuestSuspendMode mode, Error **errp) 815 { 816 SYSTEM_POWER_CAPABILITIES sys_pwr_caps; 817 Error *local_err = NULL; 818 819 ZeroMemory(&sys_pwr_caps, sizeof(sys_pwr_caps)); 820 if (!GetPwrCapabilities(&sys_pwr_caps)) { 821 error_setg(&local_err, QERR_QGA_COMMAND_FAILED, 822 "failed to determine guest suspend capabilities"); 823 goto out; 824 } 825 826 switch (mode) { 827 case GUEST_SUSPEND_MODE_DISK: 828 if (!sys_pwr_caps.SystemS4) { 829 error_setg(&local_err, QERR_QGA_COMMAND_FAILED, 830 "suspend-to-disk not supported by OS"); 831 } 832 break; 833 case GUEST_SUSPEND_MODE_RAM: 834 if (!sys_pwr_caps.SystemS3) { 835 error_setg(&local_err, QERR_QGA_COMMAND_FAILED, 836 "suspend-to-ram not supported by OS"); 837 } 838 break; 839 default: 840 error_setg(&local_err, QERR_INVALID_PARAMETER_VALUE, "mode", 841 "GuestSuspendMode"); 842 } 843 844 out: 845 if (local_err) { 846 error_propagate(errp, local_err); 847 } 848 } 849 850 static DWORD WINAPI do_suspend(LPVOID opaque) 851 { 852 GuestSuspendMode *mode = opaque; 853 DWORD ret = 0; 854 855 if (!SetSuspendState(*mode == GUEST_SUSPEND_MODE_DISK, TRUE, TRUE)) { 856 slog("failed to suspend guest, %lu", GetLastError()); 857 ret = -1; 858 } 859 g_free(mode); 860 return ret; 861 } 862 863 void qmp_guest_suspend_disk(Error **errp) 864 { 865 Error *local_err = NULL; 866 GuestSuspendMode *mode = g_malloc(sizeof(GuestSuspendMode)); 867 868 *mode = GUEST_SUSPEND_MODE_DISK; 869 check_suspend_mode(*mode, &local_err); 870 acquire_privilege(SE_SHUTDOWN_NAME, &local_err); 871 execute_async(do_suspend, mode, &local_err); 872 873 if (local_err) { 874 error_propagate(errp, local_err); 875 g_free(mode); 876 } 877 } 878 879 void qmp_guest_suspend_ram(Error **errp) 880 { 881 Error *local_err = NULL; 882 GuestSuspendMode *mode = g_malloc(sizeof(GuestSuspendMode)); 883 884 *mode = GUEST_SUSPEND_MODE_RAM; 885 check_suspend_mode(*mode, &local_err); 886 acquire_privilege(SE_SHUTDOWN_NAME, &local_err); 887 execute_async(do_suspend, mode, &local_err); 888 889 if (local_err) { 890 error_propagate(errp, local_err); 891 g_free(mode); 892 } 893 } 894 895 void qmp_guest_suspend_hybrid(Error **errp) 896 { 897 error_setg(errp, QERR_UNSUPPORTED); 898 } 899 900 static IP_ADAPTER_ADDRESSES *guest_get_adapters_addresses(Error **errp) 901 { 902 IP_ADAPTER_ADDRESSES *adptr_addrs = NULL; 903 ULONG adptr_addrs_len = 0; 904 DWORD ret; 905 906 /* Call the first time to get the adptr_addrs_len. */ 907 GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, 908 NULL, adptr_addrs, &adptr_addrs_len); 909 910 adptr_addrs = g_malloc(adptr_addrs_len); 911 ret = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, 912 NULL, adptr_addrs, &adptr_addrs_len); 913 if (ret != ERROR_SUCCESS) { 914 error_setg_win32(errp, ret, "failed to get adapters addresses"); 915 g_free(adptr_addrs); 916 adptr_addrs = NULL; 917 } 918 return adptr_addrs; 919 } 920 921 static char *guest_wctomb_dup(WCHAR *wstr) 922 { 923 char *str; 924 size_t i; 925 926 i = wcslen(wstr) + 1; 927 str = g_malloc(i); 928 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, 929 wstr, -1, str, i, NULL, NULL); 930 return str; 931 } 932 933 static char *guest_addr_to_str(IP_ADAPTER_UNICAST_ADDRESS *ip_addr, 934 Error **errp) 935 { 936 char addr_str[INET6_ADDRSTRLEN + INET_ADDRSTRLEN]; 937 DWORD len; 938 int ret; 939 940 if (ip_addr->Address.lpSockaddr->sa_family == AF_INET || 941 ip_addr->Address.lpSockaddr->sa_family == AF_INET6) { 942 len = sizeof(addr_str); 943 ret = WSAAddressToString(ip_addr->Address.lpSockaddr, 944 ip_addr->Address.iSockaddrLength, 945 NULL, 946 addr_str, 947 &len); 948 if (ret != 0) { 949 error_setg_win32(errp, WSAGetLastError(), 950 "failed address presentation form conversion"); 951 return NULL; 952 } 953 return g_strdup(addr_str); 954 } 955 return NULL; 956 } 957 958 #if (_WIN32_WINNT >= 0x0600) 959 static int64_t guest_ip_prefix(IP_ADAPTER_UNICAST_ADDRESS *ip_addr) 960 { 961 /* For Windows Vista/2008 and newer, use the OnLinkPrefixLength 962 * field to obtain the prefix. 963 */ 964 return ip_addr->OnLinkPrefixLength; 965 } 966 #else 967 /* When using the Windows XP and 2003 build environment, do the best we can to 968 * figure out the prefix. 969 */ 970 static IP_ADAPTER_INFO *guest_get_adapters_info(void) 971 { 972 IP_ADAPTER_INFO *adptr_info = NULL; 973 ULONG adptr_info_len = 0; 974 DWORD ret; 975 976 /* Call the first time to get the adptr_info_len. */ 977 GetAdaptersInfo(adptr_info, &adptr_info_len); 978 979 adptr_info = g_malloc(adptr_info_len); 980 ret = GetAdaptersInfo(adptr_info, &adptr_info_len); 981 if (ret != ERROR_SUCCESS) { 982 g_free(adptr_info); 983 adptr_info = NULL; 984 } 985 return adptr_info; 986 } 987 988 static int64_t guest_ip_prefix(IP_ADAPTER_UNICAST_ADDRESS *ip_addr) 989 { 990 int64_t prefix = -1; /* Use for AF_INET6 and unknown/undetermined values. */ 991 IP_ADAPTER_INFO *adptr_info, *info; 992 IP_ADDR_STRING *ip; 993 struct in_addr *p; 994 995 if (ip_addr->Address.lpSockaddr->sa_family != AF_INET) { 996 return prefix; 997 } 998 adptr_info = guest_get_adapters_info(); 999 if (adptr_info == NULL) { 1000 return prefix; 1001 } 1002 1003 /* Match up the passed in ip_addr with one found in adaptr_info. 1004 * The matching one in adptr_info will have the netmask. 1005 */ 1006 p = &((struct sockaddr_in *)ip_addr->Address.lpSockaddr)->sin_addr; 1007 for (info = adptr_info; info; info = info->Next) { 1008 for (ip = &info->IpAddressList; ip; ip = ip->Next) { 1009 if (p->S_un.S_addr == inet_addr(ip->IpAddress.String)) { 1010 prefix = ctpop32(inet_addr(ip->IpMask.String)); 1011 goto out; 1012 } 1013 } 1014 } 1015 out: 1016 g_free(adptr_info); 1017 return prefix; 1018 } 1019 #endif 1020 1021 GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) 1022 { 1023 IP_ADAPTER_ADDRESSES *adptr_addrs, *addr; 1024 IP_ADAPTER_UNICAST_ADDRESS *ip_addr = NULL; 1025 GuestNetworkInterfaceList *head = NULL, *cur_item = NULL; 1026 GuestIpAddressList *head_addr, *cur_addr; 1027 GuestNetworkInterfaceList *info; 1028 GuestIpAddressList *address_item = NULL; 1029 unsigned char *mac_addr; 1030 char *addr_str; 1031 WORD wsa_version; 1032 WSADATA wsa_data; 1033 int ret; 1034 1035 adptr_addrs = guest_get_adapters_addresses(errp); 1036 if (adptr_addrs == NULL) { 1037 return NULL; 1038 } 1039 1040 /* Make WSA APIs available. */ 1041 wsa_version = MAKEWORD(2, 2); 1042 ret = WSAStartup(wsa_version, &wsa_data); 1043 if (ret != 0) { 1044 error_setg_win32(errp, ret, "failed socket startup"); 1045 goto out; 1046 } 1047 1048 for (addr = adptr_addrs; addr; addr = addr->Next) { 1049 info = g_malloc0(sizeof(*info)); 1050 1051 if (cur_item == NULL) { 1052 head = cur_item = info; 1053 } else { 1054 cur_item->next = info; 1055 cur_item = info; 1056 } 1057 1058 info->value = g_malloc0(sizeof(*info->value)); 1059 info->value->name = guest_wctomb_dup(addr->FriendlyName); 1060 1061 if (addr->PhysicalAddressLength != 0) { 1062 mac_addr = addr->PhysicalAddress; 1063 1064 info->value->hardware_address = 1065 g_strdup_printf("%02x:%02x:%02x:%02x:%02x:%02x", 1066 (int) mac_addr[0], (int) mac_addr[1], 1067 (int) mac_addr[2], (int) mac_addr[3], 1068 (int) mac_addr[4], (int) mac_addr[5]); 1069 1070 info->value->has_hardware_address = true; 1071 } 1072 1073 head_addr = NULL; 1074 cur_addr = NULL; 1075 for (ip_addr = addr->FirstUnicastAddress; 1076 ip_addr; 1077 ip_addr = ip_addr->Next) { 1078 addr_str = guest_addr_to_str(ip_addr, errp); 1079 if (addr_str == NULL) { 1080 continue; 1081 } 1082 1083 address_item = g_malloc0(sizeof(*address_item)); 1084 1085 if (!cur_addr) { 1086 head_addr = cur_addr = address_item; 1087 } else { 1088 cur_addr->next = address_item; 1089 cur_addr = address_item; 1090 } 1091 1092 address_item->value = g_malloc0(sizeof(*address_item->value)); 1093 address_item->value->ip_address = addr_str; 1094 address_item->value->prefix = guest_ip_prefix(ip_addr); 1095 if (ip_addr->Address.lpSockaddr->sa_family == AF_INET) { 1096 address_item->value->ip_address_type = 1097 GUEST_IP_ADDRESS_TYPE_IPV4; 1098 } else if (ip_addr->Address.lpSockaddr->sa_family == AF_INET6) { 1099 address_item->value->ip_address_type = 1100 GUEST_IP_ADDRESS_TYPE_IPV6; 1101 } 1102 } 1103 if (head_addr) { 1104 info->value->has_ip_addresses = true; 1105 info->value->ip_addresses = head_addr; 1106 } 1107 } 1108 WSACleanup(); 1109 out: 1110 g_free(adptr_addrs); 1111 return head; 1112 } 1113 1114 int64_t qmp_guest_get_time(Error **errp) 1115 { 1116 SYSTEMTIME ts = {0}; 1117 int64_t time_ns; 1118 FILETIME tf; 1119 1120 GetSystemTime(&ts); 1121 if (ts.wYear < 1601 || ts.wYear > 30827) { 1122 error_setg(errp, "Failed to get time"); 1123 return -1; 1124 } 1125 1126 if (!SystemTimeToFileTime(&ts, &tf)) { 1127 error_setg(errp, "Failed to convert system time: %d", (int)GetLastError()); 1128 return -1; 1129 } 1130 1131 time_ns = ((((int64_t)tf.dwHighDateTime << 32) | tf.dwLowDateTime) 1132 - W32_FT_OFFSET) * 100; 1133 1134 return time_ns; 1135 } 1136 1137 void qmp_guest_set_time(bool has_time, int64_t time_ns, Error **errp) 1138 { 1139 Error *local_err = NULL; 1140 SYSTEMTIME ts; 1141 FILETIME tf; 1142 LONGLONG time; 1143 1144 if (!has_time) { 1145 /* Unfortunately, Windows libraries don't provide an easy way to access 1146 * RTC yet: 1147 * 1148 * https://msdn.microsoft.com/en-us/library/aa908981.aspx 1149 */ 1150 error_setg(errp, "Time argument is required on this platform"); 1151 return; 1152 } 1153 1154 /* Validate time passed by user. */ 1155 if (time_ns < 0 || time_ns / 100 > INT64_MAX - W32_FT_OFFSET) { 1156 error_setg(errp, "Time %" PRId64 "is invalid", time_ns); 1157 return; 1158 } 1159 1160 time = time_ns / 100 + W32_FT_OFFSET; 1161 1162 tf.dwLowDateTime = (DWORD) time; 1163 tf.dwHighDateTime = (DWORD) (time >> 32); 1164 1165 if (!FileTimeToSystemTime(&tf, &ts)) { 1166 error_setg(errp, "Failed to convert system time %d", 1167 (int)GetLastError()); 1168 return; 1169 } 1170 1171 acquire_privilege(SE_SYSTEMTIME_NAME, &local_err); 1172 if (local_err) { 1173 error_propagate(errp, local_err); 1174 return; 1175 } 1176 1177 if (!SetSystemTime(&ts)) { 1178 error_setg(errp, "Failed to set time to guest: %d", (int)GetLastError()); 1179 return; 1180 } 1181 } 1182 1183 GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp) 1184 { 1185 error_setg(errp, QERR_UNSUPPORTED); 1186 return NULL; 1187 } 1188 1189 int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp) 1190 { 1191 error_setg(errp, QERR_UNSUPPORTED); 1192 return -1; 1193 } 1194 1195 void qmp_guest_set_user_password(const char *username, 1196 const char *password, 1197 bool crypted, 1198 Error **errp) 1199 { 1200 error_setg(errp, QERR_UNSUPPORTED); 1201 } 1202 1203 GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp) 1204 { 1205 error_setg(errp, QERR_UNSUPPORTED); 1206 return NULL; 1207 } 1208 1209 GuestMemoryBlockResponseList * 1210 qmp_guest_set_memory_blocks(GuestMemoryBlockList *mem_blks, Error **errp) 1211 { 1212 error_setg(errp, QERR_UNSUPPORTED); 1213 return NULL; 1214 } 1215 1216 GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp) 1217 { 1218 error_setg(errp, QERR_UNSUPPORTED); 1219 return NULL; 1220 } 1221 1222 /* add unsupported commands to the blacklist */ 1223 GList *ga_command_blacklist_init(GList *blacklist) 1224 { 1225 const char *list_unsupported[] = { 1226 "guest-suspend-hybrid", 1227 "guest-get-vcpus", "guest-set-vcpus", 1228 "guest-set-user-password", 1229 "guest-get-memory-blocks", "guest-set-memory-blocks", 1230 "guest-get-memory-block-size", 1231 "guest-fsfreeze-freeze-list", 1232 "guest-fstrim", NULL}; 1233 char **p = (char **)list_unsupported; 1234 1235 while (*p) { 1236 blacklist = g_list_append(blacklist, *p++); 1237 } 1238 1239 if (!vss_init(true)) { 1240 g_debug("vss_init failed, vss commands are going to be disabled"); 1241 const char *list[] = { 1242 "guest-get-fsinfo", "guest-fsfreeze-status", 1243 "guest-fsfreeze-freeze", "guest-fsfreeze-thaw", NULL}; 1244 p = (char **)list; 1245 1246 while (*p) { 1247 blacklist = g_list_append(blacklist, *p++); 1248 } 1249 } 1250 1251 return blacklist; 1252 } 1253 1254 /* register init/cleanup routines for stateful command groups */ 1255 void ga_command_state_init(GAState *s, GACommandState *cs) 1256 { 1257 if (!vss_initialized()) { 1258 ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup); 1259 } 1260 ga_command_state_add(cs, guest_file_init, NULL); 1261 } 1262