Changeset 102753 in vbox for trunk/src/VBox/Additions/common/VBoxService
- Timestamp:
- Jan 3, 2024 5:24:32 PM (14 months ago)
- svn:sync-xref-src-repo-rev:
- 160930
- Location:
- trunk/src/VBox/Additions/common/VBoxService
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/common/VBoxService/VBoxServicePropCache.cpp
r98103 r102753 36 36 37 37 #include <VBox/VBoxGuestLib.h> 38 #include <VBox/HostServices/GuestPropertySvc.h> /* For GUEST_PROP_MAX_VALUE_LEN */ 38 39 #include "VBoxServiceInternal.h" 39 40 #include "VBoxServiceUtils.h" … … 214 215 * 215 216 * @returns VBox status code. 216 * 217 * @retval VERR_BUFFER_OVERFLOW if the property name or value exceeds the limit. 217 218 * @param pCache The property cache. 218 219 * @param pszName The property name. … … 227 228 228 229 Assert(pCache->uClientID); 230 231 if (RTStrNLen(pszName, GUEST_PROP_MAX_NAME_LEN) > GUEST_PROP_MAX_NAME_LEN - 1 /* Terminator */) 232 return VERR_BUFFER_OVERFLOW; 229 233 230 234 /* … … 240 244 if (!pszValue) 241 245 return VERR_NO_STR_MEMORY; 246 if (RTStrNLen(pszValue, GUEST_PROP_MAX_VALUE_LEN) > GUEST_PROP_MAX_VALUE_LEN - 1 /* Terminator */) 247 { 248 RTStrFree(pszValue); 249 return VERR_BUFFER_OVERFLOW; 250 } 242 251 } 243 252 -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo-win.cpp
r99828 r102753 37 37 #include <wtsapi32.h> /* For WTS* calls. */ 38 38 #include <psapi.h> /* EnumProcesses. */ 39 #include <sddl.h> /* For ConvertSidToStringSidW. */ 39 40 #include <Ntsecapi.h> /* Needed for process security information. */ 40 41 … … 941 942 942 943 944 /** 945 * Destroys an allocated SID. 946 * 947 * @param pSid SID to dsetroy. The pointer will be invalid on return. 948 */ 949 static void vgsvcVMInfoWinUserSidDestroy(PSID pSid) 950 { 951 RTMemFree(pSid); 952 pSid = NULL; 953 } 954 955 956 /** 957 * Looks up and returns a SID for a given user. 958 * 959 * @returns VBox status code. 960 * @param pszUser User to look up a SID for. 961 * @param ppSid Where to return the allocated SID. 962 * Must be destroyed with vgsvcVMInfoWinUserSidDestroy(). 963 */ 964 static int vgsvcVMInfoWinUserSidLookup(const char *pszUser, PSID *ppSid) 965 { 966 RTUTF16 *pwszUser = NULL; 967 size_t cwUser = 0; 968 int rc = RTStrToUtf16Ex(pszUser, RTSTR_MAX, &pwszUser, 0, &cwUser); 969 AssertRCReturn(rc, rc); 970 971 PSID pSid = NULL; 972 DWORD cbSid = 0; 973 DWORD cbDomain = 0; 974 SID_NAME_USE enmSidUse = SidTypeUser; 975 if (!LookupAccountNameW(NULL, pwszUser, pSid, &cbSid, NULL, &cbDomain, &enmSidUse)) 976 { 977 DWORD const dwErr = GetLastError(); 978 if (dwErr == ERROR_INSUFFICIENT_BUFFER) 979 { 980 pSid = (PSID)RTMemAllocZ(cbSid); 981 if (pSid) 982 { 983 PRTUTF16 pwszDomain = (PRTUTF16)RTMemAllocZ(cbDomain * sizeof(RTUTF16)); 984 if (pwszDomain) 985 { 986 if (LookupAccountNameW(NULL, pwszUser, pSid, &cbSid, pwszDomain, &cbDomain, &enmSidUse)) 987 { 988 if (IsValidSid(pSid)) 989 *ppSid = pSid; 990 else 991 rc = VERR_INVALID_PARAMETER; 992 } 993 else 994 rc = RTErrConvertFromWin32(GetLastError()); 995 } 996 else 997 rc = VERR_NO_MEMORY; 998 } 999 else 1000 rc = VERR_NO_MEMORY; 1001 } 1002 else 1003 rc = RTErrConvertFromWin32(dwErr); 1004 } 1005 else 1006 rc = RTErrConvertFromWin32(GetLastError()); 1007 1008 if (RT_FAILURE(rc)) 1009 vgsvcVMInfoWinUserSidDestroy(pSid); 1010 1011 return rc; 1012 } 1013 1014 1015 /** 1016 * Fallback function in case writing the user name failed within vgsvcVMInfoWinUserUpdateF(). 1017 * 1018 * This uses the following approach: 1019 * - only use the user name as part of the property name from now on 1020 * - write the domain name into a separate "Domain" property 1021 * - write the (full) SID into a separate "SID" property 1022 * 1023 * @returns VBox status code. 1024 * @retval VERR_BUFFER_OVERFLOW if the final property name length exceeds the maximum supported length. 1025 * @param pCache Pointer to guest property cache to update user in. 1026 * @param pszUser Name of guest user to update. 1027 * @param pszDomain Domain of guest user to update. Optional. 1028 * @param pszKey Key name of guest property to update. 1029 * @param pszValueFormat Guest property value to set. Pass NULL for deleting 1030 * the property. 1031 * @param va Variable arguments. 1032 */ 1033 int vgsvcVMInfoWinUserUpdateFallbackV(PVBOXSERVICEVEPROPCACHE pCache, const char *pszUser, const char *pszDomain, 1034 WCHAR *pwszSid, const char *pszKey, const char *pszValueFormat, va_list va) 1035 { 1036 int rc = VGSvcUserUpdateF(pCache, pszUser, NULL /* pszDomain */, "Domain", pszDomain); 1037 if (RT_SUCCESS(rc)) 1038 rc = VGSvcUserUpdateF(pCache, pszUser, NULL /* pszDomain */, "SID", "%ls", pwszSid); 1039 1040 /* Last but no least, write the actual guest property value we initially were called for. 1041 * We always do this, no matter of what the outcome from above was. */ 1042 int rc2 = VGSvcUserUpdateV(pCache, pszUser, NULL /* pszDomain */, pszKey, pszValueFormat, va); 1043 if (RT_SUCCESS(rc)) 1044 rc2 = rc; 1045 1046 return rc; 1047 } 1048 1049 1050 /** 1051 * Wrapper function for VGSvcUserUpdateF() that deals with too long guest property names. 1052 * 1053 * @return VBox status code. 1054 * @retval VERR_BUFFER_OVERFLOW if the final property name length exceeds the maximum supported length. 1055 * @param pCache Pointer to guest property cache to update user in. 1056 * @param pszUser Name of guest user to update. 1057 * @param pszDomain Domain of guest user to update. Optional. 1058 * @param pszKey Key name of guest property to update. 1059 * @param pszValueFormat Guest property value to set. Pass NULL for deleting 1060 * the property. 1061 * @param ... Variable arguments. 1062 */ 1063 int vgsvcVMInfoWinUserUpdateF(PVBOXSERVICEVEPROPCACHE pCache, const char *pszUser, const char *pszDomain, 1064 const char *pszKey, const char *pszValueFormat, ...) 1065 { 1066 va_list va; 1067 va_start(va, pszValueFormat); 1068 1069 /* First, try to write stuff as we always did, to not break older VBox versions. */ 1070 int rc = VGSvcUserUpdateV(pCache, pszUser, pszDomain, pszKey, pszValueFormat, va); 1071 if (rc == VERR_BUFFER_OVERFLOW) 1072 { 1073 /** 1074 * If the constructed property name was too long, we have to be a little more creative here: 1075 * 1076 * - only use the user name as part of the property name from now on 1077 * - write the domain name into a separate "Domain" property 1078 * - write the (full) SID into a separate "SID" property 1079 */ 1080 PSID pSid; 1081 rc = vgsvcVMInfoWinUserSidLookup(pszUser, &pSid); /** @todo Shall we cache this? */ 1082 if (RT_SUCCESS(rc)) 1083 { 1084 WCHAR *pwszSid; 1085 if (ConvertSidToStringSidW(pSid, &pwszSid)) /** @todo Ditto. */ 1086 { 1087 rc = vgsvcVMInfoWinUserUpdateFallbackV(pCache, pszUser, pszDomain, pwszSid, pszKey, pszValueFormat, va); 1088 if (RT_FAILURE(rc)) 1089 { 1090 /** 1091 * If using the sole user name as a property name still is too long or something else failed, 1092 * at least try to look up the user's RID (relative identifier). Note that the RID always is bound to the 1093 * to the authority that issued the SID. 1094 */ 1095 int const cSubAuth = *GetSidSubAuthorityCount(pSid); 1096 if (cSubAuth > 1) 1097 { 1098 DWORD const dwUserRid = *GetSidSubAuthority(pSid, cSubAuth - 1); 1099 char szUserRid[16 + 1]; 1100 if (RTStrPrintf2(szUserRid, sizeof(szUserRid), "%ld", dwUserRid) > 0) 1101 rc = vgsvcVMInfoWinUserUpdateFallbackV(pCache, szUserRid, pszDomain, pwszSid, pszKey, 1102 pszValueFormat, va); 1103 else 1104 rc = VERR_BUFFER_OVERFLOW; 1105 } 1106 /* else not much else we can do then. */ 1107 } 1108 1109 LocalFree(pwszSid); 1110 pwszSid = NULL; 1111 } 1112 else 1113 rc = RTErrConvertFromWin32(GetLastError()); 1114 1115 vgsvcVMInfoWinUserSidDestroy(pSid); 1116 } 1117 else 1118 VGSvcError("Looking up SID for user '%s' (domain '%s') failed with %Rrc\n", pszUser, pszDomain, rc); 1119 } 1120 va_end(va); 1121 return rc; 1122 } 1123 1124 943 1125 static int vgsvcVMInfoWinWriteLastInput(PVBOXSERVICEVEPROPCACHE pCache, const char *pszUser, const char *pszDomain) 944 1126 { … … 981 1163 : VBoxGuestUserState_Idle; 982 1164 983 rc = VGSvcUserUpdateF(pCache, pszUser, pszDomain, "UsageState", 984 userState == VBoxGuestUserState_InUse ? "InUse" : "Idle"); 985 1165 rc = vgsvcVMInfoWinUserUpdateF(pCache, pszUser, pszDomain, "UsageState", 1166 userState == VBoxGuestUserState_InUse ? "InUse" : "Idle"); 986 1167 /* 987 1168 * Note: vboxServiceUserUpdateF can return VINF_NO_CHANGE in case there wasn't anything … … 996 1177 /* Also write the user's current idle time, if there is any. */ 997 1178 if (userState == VBoxGuestUserState_Idle) 998 rc = vgsvcUserUpdateF(pCache, pszUser, pszDomain, "IdleTimeMs", "%RU32", ipcReply.cSecSinceLastInput); 1179 rc = vgsvcVMInfoWinUserUpdateF(pCache, pszUser, pszDomain, "IdleTimeMs", "%RU32", 1180 ipcReply.cSecSinceLastInput); 999 1181 else 1000 rc = vgsvc UserUpdateF(pCache, pszUser, pszDomain, "IdleTimeMs", NULL /* Delete property */);1001 1182 rc = vgsvcVMInfoWinUserUpdateF(pCache, pszUser, pszDomain, "IdleTimeMs", 1183 NULL /* Delete property */); 1002 1184 if (RT_SUCCESS(rc)) 1003 1185 #endif … … 1026 1208 1027 1209 /* Overwrite rc from above. */ 1028 rc = VGSvcUserUpdateF(pCache, pszUser, pszDomain, "UsageState", "Idle");1210 rc = vgsvcVMInfoWinUserUpdateF(pCache, pszUser, pszDomain, "UsageState", "Idle"); 1029 1211 1030 1212 fReportToHost = rc == VINF_SUCCESS; -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo.cpp
r102716 r102753 108 108 #include <VBox/version.h> 109 109 #include <VBox/VBoxGuestLib.h> 110 #include <VBox/HostServices/GuestPropertySvc.h> /* For GUEST_PROP_MAX_VALUE_LEN */ 110 111 #include "VBoxServiceInternal.h" 111 112 #include "VBoxServiceUtils.h" … … 145 146 static const char *g_pszPropCacheValNetCount = "/VirtualBox/GuestInfo/Net/Count"; 146 147 /** A guest user's guest property root key. */ 147 static const char *g_pszPropCache ValUser = "/VirtualBox/GuestInfo/User/";148 static const char *g_pszPropCacheKeyUser = "/VirtualBox/GuestInfo/User"; 148 149 /** The VM session ID. Changes whenever the VM is restored or reset. */ 149 150 static uint64_t g_idVMInfoSession; … … 419 420 * Updates a per-guest user guest property inside the given property cache. 420 421 * 421 * @return IPRT status code. 422 * @return VBox status code. 423 * @retval VERR_BUFFER_OVERFLOW if the final property name length exceeds the maximum supported length. 422 424 * @param pCache Pointer to guest property cache to update user in. 423 425 * @param pszUser Name of guest user to update. … … 436 438 /* pszValueFormat is optional. */ 437 439 440 /** Historically we limit guest property names to 64 characters (see GUEST_PROP_MAX_NAME_LEN, including terminator). 441 * So we need to make sure the stuff we want to write as a value fits into that space. See bugref{10575}. */ 442 443 /* Try to write things the legacy way first. */ 444 char szName[GUEST_PROP_MAX_NAME_LEN]; 445 AssertCompile(GUEST_PROP_MAX_NAME_LEN == 64); /* Can we improve stuff once we (ever) raise this limit? */ 446 ssize_t const cchVal = pszDomain 447 ? RTStrPrintf2(szName, sizeof(szName), "%s/%s@%s/%s", g_pszPropCacheKeyUser, pszUser, pszDomain, pszKey) 448 : RTStrPrintf2(szName, sizeof(szName), "%s/%s/%s", g_pszPropCacheKeyUser, pszUser, pszKey); 449 450 /* Did we exceed the length limit? Tell the caller to try again with some more sane values. */ 451 if (cchVal < 0) 452 return VERR_BUFFER_OVERFLOW; 453 438 454 int rc = VINF_SUCCESS; 439 455 440 /** @todo r=bird: This is just asking for trouble with long names, esp. when441 * domain names are included. The max property name limit is 64 characters,442 * so it is really easy to run into the limit here. E.g.443 * "/VirtualBox/GuestInfo/User/Administrator@DGV-W10X64-TEST/UsageState"444 * is too long and will be rejected by the host servce (assert in strict builds)445 * as Dmitrii just observed.446 *447 * A slightly more managable design here would've been to use the user ID rather448 * than the user name. Not sure how this would work for domains, though, these449 * can probably be pretty long as well. Any numeric/fixed-sized IDs for domains?450 * Since these mistakes have been made already, perhaps use the UID as a451 * fallback?452 *453 * Also, since we're working a max length limit here, WTF do we use454 * RTStrAPrintf? We could use a fixed buffer size and RTStrPrintf2 and detect455 * the problem here before we even get to the host side.456 */457 char *pszName;458 if (pszDomain)459 {460 if (RTStrAPrintf(&pszName, "%s%s@%s/%s", g_pszPropCacheValUser, pszUser, pszDomain, pszKey) < 0)461 rc = VERR_NO_MEMORY;462 }463 else464 {465 if (RTStrAPrintf(&pszName, "%s%s/%s", g_pszPropCacheValUser, pszUser, pszKey) < 0)466 rc = VERR_NO_MEMORY;467 }468 469 456 char *pszValue = NULL; 470 if ( RT_SUCCESS(rc) 471 && pszValueFormat) 457 if (pszValueFormat) 472 458 { 473 459 va_list va; … … 482 468 483 469 if (RT_SUCCESS(rc)) 484 rc = VGSvcPropCacheUpdate(pCache, pszName, pszValue);470 rc = VGSvcPropCacheUpdate(pCache, szName, pszValue); 485 471 if (rc == VINF_SUCCESS) /* VGSvcPropCacheUpdate will also return VINF_NO_CHANGE. */ 486 472 { 487 473 /** @todo Combine updating flags w/ updating the actual value. */ 488 rc = VGSvcPropCacheUpdateEntry(pCache, pszName,474 rc = VGSvcPropCacheUpdateEntry(pCache, szName, 489 475 VGSVCPROPCACHE_FLAGS_TEMPORARY | VGSVCPROPCACHE_FLAGS_TRANSIENT, 490 476 NULL /* Delete on exit */); … … 492 478 493 479 RTStrFree(pszValue); 494 RTStrFree(pszName); 480 return rc; 481 } 482 483 484 /** 485 * Updates a per-guest user guest property inside the given property cache. 486 * 487 * @return VBox status code. 488 * @retval VERR_BUFFER_OVERFLOW if the final property name length exceeds the maximum supported length. 489 * @param pCache Pointer to guest property cache to update user in. 490 * @param pszUser Name of guest user to update. 491 * @param pszDomain Domain of guest user to update. Optional. 492 * @param pszKey Key name of guest property to update. 493 * @param pszFormat Format string to set. Pass NULL for deleting the property. 494 * @param va Format arguments. 495 */ 496 int VGSvcUserUpdateV(PVBOXSERVICEVEPROPCACHE pCache, const char *pszUser, const char *pszDomain, 497 const char *pszKey, const char *pszFormat, va_list va) 498 { 499 char *psz = NULL; 500 if (pszFormat) /* Might be NULL to delete a property. */ 501 { 502 if (RTStrAPrintfV(&psz, pszFormat, va) < 0) 503 return VERR_NO_MEMORY; 504 } 505 int const rc = VGSvcUserUpdateF(pCache, pszUser, pszDomain, pszKey, psz); 506 RTStrFree(psz); 495 507 return rc; 496 508 } -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo.h
r98103 r102753 35 35 extern int VGSvcUserUpdateF(PVBOXSERVICEVEPROPCACHE pCache, const char *pszUser, const char *pszDomain, 36 36 const char *pszKey, const char *pszValueFormat, ...); 37 extern int VGSvcUserUpdateV(PVBOXSERVICEVEPROPCACHE pCache, const char *pszUser, const char *pszDomain, 38 const char *pszKey, const char *pszFormat, va_list va); 37 39 40 extern int vgsvcVMInfoWinUserUpdateF(PVBOXSERVICEVEPROPCACHE pCache, const char *pszUser, const char *pszDomain, 41 const char *pszKey, const char *pszValueFormat, ...); 38 42 39 43 extern uint32_t g_uVMInfoUserIdleThresholdMS;
Note:
See TracChangeset
for help on using the changeset viewer.