1 /* 2 * PROJECT: ReactOS Application compatibility module 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Shim database query functions 5 * COPYRIGHT: Copyright 2011 André Hentschel 6 * Copyright 2013 Mislav Blaževic 7 * Copyright 2015-2017 Mark Jansen (mark.jansen@reactos.org) 8 */ 9 10 #include "windef.h" 11 #include "apphelp.h" 12 13 14 DWORD WINAPI SdbGetTagDataSize(PDB pdb, TAGID tagid); 15 16 17 BOOL WINAPI SdbpReadData(PDB pdb, PVOID dest, DWORD offset, DWORD num) 18 { 19 DWORD size = offset + num; 20 21 /* Either overflow or no data to read */ 22 if (size <= offset) 23 return FALSE; 24 25 /* Overflow */ 26 if (pdb->size < size) 27 return FALSE; 28 29 memcpy(dest, pdb->data + offset, num); 30 return TRUE; 31 } 32 33 static DWORD WINAPI SdbpGetTagSize(PDB pdb, TAGID tagid) 34 { 35 WORD type; 36 DWORD size; 37 38 type = SdbGetTagFromTagID(pdb, tagid) & TAG_TYPE_MASK; 39 if (type == TAG_NULL) 40 return 0; 41 42 size = SdbGetTagDataSize(pdb, tagid); 43 if (type <= TAG_TYPE_STRINGREF) 44 return size += sizeof(TAG); 45 else size += (sizeof(TAG) + sizeof(DWORD)); 46 47 return size; 48 } 49 50 static LPWSTR WINAPI SdbpGetString(PDB pdb, TAGID tagid, PDWORD size) 51 { 52 TAG tag; 53 TAGID offset; 54 55 tag = SdbGetTagFromTagID(pdb, tagid); 56 if (tag == TAG_NULL) 57 return NULL; 58 59 if ((tag & TAG_TYPE_MASK) == TAG_TYPE_STRINGREF) 60 { 61 /* No stringtable; all references are invalid */ 62 if (pdb->stringtable == TAGID_NULL) 63 return NULL; 64 65 /* TAG_TYPE_STRINGREF contains offset of string relative to stringtable */ 66 if (!SdbpReadData(pdb, &tagid, tagid + sizeof(TAG), sizeof(TAGID))) 67 return NULL; 68 69 offset = pdb->stringtable + tagid + sizeof(TAG) + sizeof(TAGID); 70 } 71 else if ((tag & TAG_TYPE_MASK) == TAG_TYPE_STRING) 72 { 73 offset = tagid + sizeof(TAG) + sizeof(TAGID); 74 } 75 else 76 { 77 SHIM_ERR("Tag 0x%u at tagid %u is neither a string or reference to string\n", tag, tagid); 78 return NULL; 79 } 80 81 /* Optionally read string size */ 82 if (size && !SdbpReadData(pdb, size, tagid + sizeof(TAG), sizeof(*size))) 83 return FALSE; 84 85 return (LPWSTR)(&pdb->data[offset]); 86 } 87 88 /** 89 * Searches shim database for the tag associated with specified tagid. 90 * 91 * @param [in] pdb Handle to the shim database. 92 * @param [in] tagid The TAGID of the tag. 93 * 94 * @return Success: The tag associated with specified tagid, Failure: TAG_NULL. 95 */ 96 TAG WINAPI SdbGetTagFromTagID(PDB pdb, TAGID tagid) 97 { 98 TAG data; 99 if (!SdbpReadData(pdb, &data, tagid, sizeof(data))) 100 return TAG_NULL; 101 return data; 102 } 103 104 /** 105 * Retrieves size of data at specified tagid. 106 * 107 * @param [in] pdb Handle to the shim database. 108 * @param [in] tagid Tagid of tag whose size is queried. 109 * 110 * @return Success: Size of data at specified tagid, Failure: 0. 111 */ 112 DWORD WINAPI SdbGetTagDataSize(PDB pdb, TAGID tagid) 113 { 114 /* sizes of data types with fixed size */ 115 static const SIZE_T sizes[6] = { 116 0, /* NULL */ 1, /* BYTE */ 117 2, /* WORD */ 4, /* DWORD */ 118 8, /* QWORD */ 4 /* STRINGREF */ 119 }; 120 WORD type; 121 DWORD size; 122 123 type = SdbGetTagFromTagID(pdb, tagid) & TAG_TYPE_MASK; 124 if (type == TAG_NULL) 125 return 0; 126 127 if (type <= TAG_TYPE_STRINGREF) 128 return sizes[(type >> 12) - 1]; 129 130 /* tag with dynamic size (e.g. list): must read size */ 131 if (!SdbpReadData(pdb, &size, tagid + sizeof(TAG), sizeof(size))) 132 return 0; 133 134 return size; 135 } 136 137 /** 138 * Searches shim database for a child of specified parent tag. 139 * 140 * @param [in] pdb Handle to the shim database. 141 * @param [in] parent TAGID of parent. 142 * 143 * @return Success: TAGID of child tag, Failure: TAGID_NULL. 144 */ 145 TAGID WINAPI SdbGetFirstChild(PDB pdb, TAGID parent) 146 { 147 /* if we are at beginning of database */ 148 if (parent == TAGID_ROOT) 149 { 150 /* header only database: no tags */ 151 if (pdb->size <= _TAGID_ROOT) 152 return TAGID_NULL; 153 /* return *real* root tagid */ 154 else return _TAGID_ROOT; 155 } 156 157 /* only list tag can have children */ 158 if ((SdbGetTagFromTagID(pdb, parent) & TAG_TYPE_MASK) != TAG_TYPE_LIST) 159 return TAGID_NULL; 160 161 /* first child is sizeof(TAG) + sizeof(DWORD) bytes after beginning of list */ 162 return parent + sizeof(TAG) + sizeof(DWORD); 163 } 164 165 /** 166 * Searches shim database for next child of specified parent tag. 167 * 168 * @param [in] pdb Handle to the shim database. 169 * @param [in] parent TAGID of parent. 170 * @param [in] prev_child TAGID of previous child. 171 * 172 * @return Success: TAGID of next child tag, Failure: TAGID_NULL. 173 */ 174 TAGID WINAPI SdbGetNextChild(PDB pdb, TAGID parent, TAGID prev_child) 175 { 176 TAGID next_child; 177 DWORD prev_child_size, parent_size; 178 179 prev_child_size = SdbpGetTagSize(pdb, prev_child); 180 if (prev_child_size == 0) 181 return TAGID_NULL; 182 183 /* Bound check */ 184 next_child = prev_child + prev_child_size; 185 if (next_child >= pdb->size) 186 return TAGID_NULL; 187 188 if (parent == TAGID_ROOT) 189 return next_child; 190 191 parent_size = SdbpGetTagSize(pdb, parent); 192 if (parent_size == 0) 193 return TAGID_NULL; 194 195 /* Specified parent has no more children */ 196 if (next_child >= parent + parent_size) 197 return TAGID_NULL; 198 199 return next_child; 200 } 201 202 /** 203 * Searches shim database for a tag within specified domain. 204 * 205 * @param [in] pdb Handle to the shim database. 206 * @param [in] parent TAGID of parent. 207 * @param [in] tag TAG to be located. 208 * 209 * @return Success: TAGID of first matching tag, Failure: TAGID_NULL. 210 */ 211 TAGID WINAPI SdbFindFirstTag(PDB pdb, TAGID parent, TAG tag) 212 { 213 TAGID iter; 214 215 iter = SdbGetFirstChild(pdb, parent); 216 while (iter != TAGID_NULL) 217 { 218 if (SdbGetTagFromTagID(pdb, iter) == tag) 219 return iter; 220 iter = SdbGetNextChild(pdb, parent, iter); 221 } 222 return TAGID_NULL; 223 } 224 225 /** 226 * Searches shim database for a next tag which matches prev_child within parent's domain. 227 * 228 * @param [in] pdb Handle to the shim database. 229 * @param [in] parent TAGID of parent. 230 * @param [in] prev_child TAGID of previous match. 231 * 232 * @return Success: TAGID of next match, Failure: TAGID_NULL. 233 */ 234 TAGID WINAPI SdbFindNextTag(PDB pdb, TAGID parent, TAGID prev_child) 235 { 236 TAG tag; 237 TAGID iter; 238 239 tag = SdbGetTagFromTagID(pdb, prev_child); 240 iter = SdbGetNextChild(pdb, parent, prev_child); 241 242 while (iter != TAGID_NULL) 243 { 244 if (SdbGetTagFromTagID(pdb, iter) == tag) 245 return iter; 246 iter = SdbGetNextChild(pdb, parent, iter); 247 } 248 return TAGID_NULL; 249 } 250 251 /** 252 * Searches shim database for string associated with specified tagid and copies string into a 253 * buffer. 254 * 255 * If size parameter is less than number of characters in string, this function shall fail and 256 * no data shall be copied. 257 * 258 * @param [in] pdb Handle to the shim database. 259 * @param [in] tagid TAGID of string or stringref associated with the string. 260 * @param [out] buffer Buffer in which string will be copied. 261 * @param [in] size Number of characters to copy. 262 * 263 * @return TRUE if string was successfully copied to the buffer FALSE if string was not copied 264 * to the buffer. 265 */ 266 BOOL WINAPI SdbReadStringTag(PDB pdb, TAGID tagid, LPWSTR buffer, DWORD size) 267 { 268 LPWSTR string; 269 DWORD string_size; 270 271 string = SdbpGetString(pdb, tagid, &string_size); 272 if (!string) 273 return FALSE; 274 275 /* Check if buffer is too small */ 276 if (size * sizeof(WCHAR) < string_size) 277 return FALSE; 278 279 memcpy(buffer, string, string_size); 280 return TRUE; 281 } 282 283 /** 284 * Reads WORD value at specified tagid. 285 * 286 * @param [in] pdb Handle to the shim database. 287 * @param [in] tagid TAGID of WORD value. 288 * @param [in] ret Default return value in case function fails. 289 * 290 * @return Success: WORD value at specified tagid, or ret on failure. 291 */ 292 WORD WINAPI SdbReadWORDTag(PDB pdb, TAGID tagid, WORD ret) 293 { 294 if (SdbpCheckTagIDType(pdb, tagid, TAG_TYPE_WORD)) 295 SdbpReadData(pdb, &ret, tagid + 2, sizeof(WORD)); 296 return ret; 297 } 298 299 /** 300 * Reads DWORD value at specified tagid. 301 * 302 * @param [in] pdb Handle to the shim database. 303 * @param [in] tagid TAGID of DWORD value. 304 * @param [in] ret Default return value in case function fails. 305 * 306 * @return Success: DWORD value at specified tagid, otherwise ret. 307 */ 308 DWORD WINAPI SdbReadDWORDTag(PDB pdb, TAGID tagid, DWORD ret) 309 { 310 if (SdbpCheckTagIDType(pdb, tagid, TAG_TYPE_DWORD)) 311 SdbpReadData(pdb, &ret, tagid + 2, sizeof(DWORD)); 312 return ret; 313 } 314 315 /** 316 * Reads QWORD value at specified tagid. 317 * 318 * @param [in] pdb Handle to the shim database. 319 * @param [in] tagid TAGID of QWORD value. 320 * @param [in] ret Default return value in case function fails. 321 * 322 * @return Success: QWORD value at specified tagid, otherwise ret. 323 */ 324 QWORD WINAPI SdbReadQWORDTag(PDB pdb, TAGID tagid, QWORD ret) 325 { 326 if (SdbpCheckTagIDType(pdb, tagid, TAG_TYPE_QWORD)) 327 SdbpReadData(pdb, &ret, tagid + sizeof(TAG), sizeof(QWORD)); 328 return ret; 329 } 330 331 /** 332 * Reads binary data at specified tagid. 333 * 334 * @param [in] pdb Handle to the shim database. 335 * @param [in] tagid TAGID of binary data. 336 * @param [out] buffer Buffer in which data will be copied. 337 * @param [in] size Size of the buffer. 338 * 339 * @return TRUE if data was successfully written, or FALSE otherwise. 340 */ 341 BOOL WINAPI SdbReadBinaryTag(PDB pdb, TAGID tagid, PBYTE buffer, DWORD size) 342 { 343 DWORD data_size = 0; 344 345 if (SdbpCheckTagIDType(pdb, tagid, TAG_TYPE_BINARY)) 346 { 347 SdbpReadData(pdb, &data_size, tagid + sizeof(TAG), sizeof(data_size)); 348 if (size >= data_size) 349 return SdbpReadData(pdb, buffer, tagid + sizeof(TAG) + sizeof(data_size), data_size); 350 } 351 352 return FALSE; 353 } 354 355 /** 356 * Retrieves binary data at specified tagid. 357 * 358 * @param [in] pdb Handle to the shim database. 359 * @param [in] tagid TAGID of binary data. 360 * 361 * @return Success: Pointer to binary data at specified tagid, or NULL on failure. 362 */ 363 PVOID WINAPI SdbGetBinaryTagData(PDB pdb, TAGID tagid) 364 { 365 if (!SdbpCheckTagIDType(pdb, tagid, TAG_TYPE_BINARY)) 366 return NULL; 367 return &pdb->data[tagid + sizeof(TAG) + sizeof(DWORD)]; 368 } 369 370 /** 371 * Searches shim database for string associated with specified tagid. 372 * 373 * @param [in] pdb Handle to the shim database. 374 * @param [in] tagid TAGID of string or stringref associated with the string. 375 * 376 * @return the LPWSTR associated with specified tagid, or NULL on failure. 377 */ 378 LPWSTR WINAPI SdbGetStringTagPtr(PDB pdb, TAGID tagid) 379 { 380 return SdbpGetString(pdb, tagid, NULL); 381 } 382 383 /** 384 * Reads binary data at specified tagid. 385 * 386 * @param [in] pdb Handle to the shim database. 387 * @param [out] Guid Database ID. 388 * 389 * @return true if the ID was found FALSE otherwise. 390 */ 391 BOOL WINAPI SdbGetDatabaseID(PDB pdb, GUID* Guid) 392 { 393 if(SdbIsNullGUID(&pdb->database_id)) 394 { 395 TAGID root = SdbFindFirstTag(pdb, TAGID_ROOT, TAG_DATABASE); 396 if(root != TAGID_NULL) 397 { 398 TAGID id = SdbFindFirstTag(pdb, root, TAG_DATABASE_ID); 399 if(id != TAGID_NULL) 400 { 401 if(!SdbReadBinaryTag(pdb, id, (PBYTE)&pdb->database_id, sizeof(pdb->database_id))) 402 { 403 memset(&pdb->database_id, 0, sizeof(pdb->database_id)); 404 } 405 } 406 else 407 { 408 /* Should we silence this if we are opening a system db? */ 409 SHIM_ERR("Failed to get the database id\n"); 410 } 411 } 412 else 413 { 414 /* Should we silence this if we are opening a system db? */ 415 SHIM_ERR("Failed to get root tag\n"); 416 } 417 } 418 if(!SdbIsNullGUID(&pdb->database_id)) 419 { 420 memcpy(Guid, &pdb->database_id, sizeof(pdb->database_id)); 421 return TRUE; 422 } 423 return FALSE; 424 } 425 426