Changeset 262
- Timestamp:
- 06/17/11 13:51:31 (14 years ago)
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
test/pyregfi-smoketest.py
r255 r262 65 65 path = getCurrentPath(k) 66 66 try: 67 print(repr(path)) 67 68 hive_iter = hive.subtree(path) 68 69 if hive_iter.current_key() != k: … … 174 175 ssk = hive_iter.find_subkey(sk.name) 175 176 if ssk != None: 176 sk_stat += len(ssk.name) 177 if ssk.name != None: 178 sk_stat += len(ssk.name) 177 179 else: 178 180 print("WARNING: ssk was None") … … 183 185 vv = hive_iter.find_value(v.name) 184 186 if vv != None: 185 v_stat += len(vv.name) 187 if vv.name != None: 188 v_stat += len(vv.name) 186 189 else: 187 190 print("WARNING: vv was None") … … 230 233 231 234 def loopSecurity(hive, fh): 232 start = hive.root.fetch_security() 233 print(start.descriptor.group) 234 cur = start.next_security() 235 236 while cur != start: 237 print(start.descriptor.group) 238 cur = cur.next_security() 235 cur = hive.root.fetch_security() 236 while True: 237 stat += len(cur.descriptor.owner) 238 stat += len(cur.descriptor.group) 239 if cur.descriptor.sacl: 240 stat += len(cur.descriptor.sacl) 241 if cur.descriptor.dacl: 242 stat += len(cur.descriptor.dacl) 243 244 nxt = cur.next_security() 245 if cur == nxt: 246 break 239 247 240 248 … … 278 286 279 287 def usage(): 280 sys.stderr.write("USAGE: pyregfi-smoketest.py test1[,test2[,...]]hive1 [hive2 ...]\n")288 sys.stderr.write("USAGE: pyregfi-smoketest.py { test1[,test2[,...]] | * } hive1 [hive2 ...]\n") 281 289 sys.stderr.write("\tAvailable tests:\n") 282 290 for t in tests.keys(): … … 288 296 sys.exit(1) 289 297 290 selected_tests = sys.argv[1].split(',') 291 for st in selected_tests: 292 if st not in tests: 293 usage() 294 sys.stderr.write("ERROR: %s not a valid test type\n\n" % st) 295 sys.exit(1) 298 if sys.argv[1] == '*': 299 selected_tests = tests.keys() 300 else: 301 selected_tests = sys.argv[1].split(',') 302 for st in selected_tests: 303 if st not in tests: 304 usage() 305 sys.stderr.write("ERROR: %s not a valid test type\n\n" % st) 306 sys.exit(1) 296 307 297 308 files = [] -
trunk/doc/devel/TODO
r250 r262 15 15 descriptor information. Maybe by MTIME as well. 16 16 17 - reglookup-timeline needs to be replaced with something cross-platform. 18 Perhaps a python script that provides MTIME range filtering capabilities. 19 20 - Need to integrate much of reglookup-recover's algorithms into regfi 21 and then expose them from the bottom-up to provide building blocks 22 through regfi and pyregfi. This should be addressed along with code 23 to support handling of partial/fragmented registry hives. 24 17 25 - Testing, testing, and more testing. reglookup needs to be more 18 26 heavily tested on all recent Windows platforms. A regression test … … 26 34 to be decent, UTF-8 output would be nice. 27 35 28 - Develop and solidify regfi API. Regfi should be better documented and 29 eventually needs a set of higher-language wrappers, starting with Python 30 and possibly moving on to Perl as well. 36 - Continue to improve regfi/pyregfi APIs as needed. winsec library needs more 37 flexibility and documentation. 38 39 - Consider adding regfi wrappers for other high-level languages (perl? ruby?). 31 40 32 41 - Documentation. The security descriptor output format needs to be 33 42 documented. Also, function contracts should be added to the 34 lower-level functions of regfi.c. 43 lower-level functions of regfi.c. Continue adding 35 44 36 45 - Consider switching from libiconv to Joachim Metz's libuna for … … 39 48 - Grep through the source for 'XXX', and you'll find more. 40 49 50 - Consider integrating packaging rules for debian/other platforms into trunk. 51 52 - Investigate why file descriptors can't be directly used in Windows 41 53 42 54 … … 44 56 =========== 45 57 46 Add fields/methods for accessing security descriptors in pyregfi47 48 convert MTIME structure to uint64_t if possible49 50 investigate why file descriptors can't be directly used in Windows51 52 Fill in and update remaining regfi/pyregfi API documentation53 54 Possible debian package build rules55 56 Possibly replace reglookup-timeline with something cross-platform57 58 58 Testing 59 59 Full diffs 60 60 regfi and pyregfi threading 61 61 valgrind in multiple scenarios for reglookup, reglookup-recover 62 62 double check man pages -
trunk/include/regfi.h
r258 r262 1 1 /* 2 * Copyright (C) 2005-201 0Timothy D. Morgan2 * Copyright (C) 2005-2011 Timothy D. Morgan 3 3 * Copyright (C) 2010 Michael Cohen 4 4 * Copyright (C) 2005 Gerald (Jerry) Carter … … 1152 1152 * @param file the file from which key is derived 1153 1153 * @param key the key whose subkey is desired 1154 * @param name name of the desired subkey 1154 * @param name name of the desired subkey (case-insensitive) 1155 1155 * @param index a return value: the index of the desired subkey. 1156 1156 * undefined on error … … 1171 1171 * @param file the file from which key is derived 1172 1172 * @param key the key whose value is desired 1173 * @param name name of the desired value 1173 * @param name name of the desired value (case-insensitive) 1174 1174 * @param index a return value: the index of the desired value. 1175 1175 * undefined on error … … 1753 1753 _EXPORT() 1754 1754 int32_t regfi_calc_maxsize(REGFI_FILE* file, uint32_t offset); 1755 int32_t regfi_conv_charset(const char* input_charset, 1756 const char* output_charset, 1757 uint8_t* input, char* output, 1758 uint32_t input_len, uint32_t output_max); 1755 REGFI_BUFFER regfi_conv_charset(const char* input_charset, const char* output_charset, 1756 uint8_t* input, uint32_t input_len); 1759 1757 _EXPORT() 1760 1758 REGFI_DATA* regfi_buffer_to_data(REGFI_BUFFER raw_data); -
trunk/lib/regfi.c
r261 r262 1186 1186 * when recovering deleted VK records. 1187 1187 */ 1188 int32_t tmp_size;1188 REGFI_BUFFER tmp_buf; 1189 1189 REGFI_ENCODING from_encoding = (vk->flags & REGFI_VK_FLAG_ASCIINAME) 1190 1190 ? REGFI_ENCODING_ASCII : REGFI_ENCODING_UTF16LE; … … 1200 1200 else 1201 1201 { 1202 vk->name = talloc_array(vk, char, vk->name_length+1); 1203 if(vk->name == NULL) 1204 return; 1205 1206 tmp_size = regfi_conv_charset(regfi_encoding_int2str(from_encoding), 1207 regfi_encoding_int2str(output_encoding), 1208 vk->name_raw, vk->name, 1209 vk->name_length, vk->name_length+1); 1210 if(tmp_size < 0) 1202 tmp_buf = regfi_conv_charset(regfi_encoding_int2str(from_encoding), 1203 regfi_encoding_int2str(output_encoding), 1204 vk->name_raw, vk->name_length); 1205 if(tmp_buf.buf == NULL) 1211 1206 { 1212 1207 regfi_log_add(REGFI_LOG_WARN, "Error occurred while converting" 1213 1208 " value name to encoding %s. Error message: %s", 1214 1209 regfi_encoding_int2str(output_encoding), 1215 strerror(-tmp_size)); 1216 talloc_free(vk->name); 1210 strerror(errno)); 1217 1211 vk->name = NULL; 1212 } 1213 else 1214 { 1215 vk->name = (char*)tmp_buf.buf; 1216 talloc_reparent(NULL, vk, vk->name); 1218 1217 } 1219 1218 } … … 1280 1279 * when recovering deleted NK records. 1281 1280 */ 1282 int32_t tmp_size;1281 REGFI_BUFFER tmp_buf; 1283 1282 REGFI_ENCODING from_encoding = (nk->flags & REGFI_NK_FLAG_ASCIINAME) 1284 1283 ? REGFI_ENCODING_ASCII : REGFI_ENCODING_UTF16LE; … … 1294 1293 else 1295 1294 { 1296 nk->name = talloc_array(nk, char, nk->name_length+1); 1297 if(nk->name == NULL) 1298 return; 1299 1300 memset(nk->name,0,nk->name_length+1); 1301 1302 tmp_size = regfi_conv_charset(regfi_encoding_int2str(from_encoding), 1303 regfi_encoding_int2str(output_encoding), 1304 nk->name_raw, nk->name, 1305 nk->name_length, nk->name_length+1); 1306 if(tmp_size < 0) 1295 tmp_buf = regfi_conv_charset(regfi_encoding_int2str(from_encoding), 1296 regfi_encoding_int2str(output_encoding), 1297 nk->name_raw, nk->name_length); 1298 if(tmp_buf.buf == NULL) 1307 1299 { 1308 1300 regfi_log_add(REGFI_LOG_WARN, "Error occurred while converting" 1309 " key name to encoding %s. Error message: %s", 1310 regfi_encoding_int2str(output_encoding), 1311 strerror(-tmp_size)); 1312 talloc_free(nk->name); 1301 " key name to encoding %s. Error message: %s", 1302 regfi_encoding_int2str(output_encoding), 1303 strerror(errno)); 1313 1304 nk->name = NULL; 1305 } 1306 else 1307 { 1308 nk->name = (char*)tmp_buf.buf; 1309 talloc_reparent(NULL, nk, nk->name); 1314 1310 } 1315 1311 } … … 2243 2239 REGFI_CLASSNAME* ret_val; 2244 2240 uint8_t* raw; 2245 char* interpreted;2241 REGFI_BUFFER tmp_buf; 2246 2242 uint32_t offset; 2247 int32_t conv_size,max_size;2243 int32_t max_size; 2248 2244 uint16_t parse_length; 2249 2245 … … 2276 2272 talloc_reparent(NULL, ret_val, raw); 2277 2273 2278 interpreted = talloc_array(NULL, char, parse_length); 2279 2280 conv_size = regfi_conv_charset(regfi_encoding_int2str(REGFI_ENCODING_UTF16LE), 2281 regfi_encoding_int2str(file->string_encoding), 2282 raw, interpreted, 2283 parse_length, parse_length); 2284 if(conv_size < 0) 2274 tmp_buf = regfi_conv_charset(regfi_encoding_int2str(REGFI_ENCODING_UTF16LE), 2275 regfi_encoding_int2str(file->string_encoding), 2276 raw, parse_length); 2277 if(tmp_buf.buf == NULL) 2285 2278 { 2286 2279 regfi_log_add(REGFI_LOG_WARN, "Error occurred while" 2287 2280 " converting classname to charset %s. Error message: %s", 2288 file->string_encoding, strerror(-conv_size)); 2289 talloc_free(interpreted); 2281 file->string_encoding, strerror(errno)); 2290 2282 ret_val->interpreted = NULL; 2291 2283 } 2292 2284 else 2293 2285 { 2294 /* XXX: check for NULL return here? */ 2295 interpreted = talloc_realloc(NULL, interpreted, char, conv_size); 2296 ret_val->interpreted = interpreted; 2297 talloc_reparent(NULL, ret_val, interpreted); 2286 ret_val->interpreted = (char*)tmp_buf.buf; 2287 talloc_reparent(NULL, ret_val, tmp_buf.buf); 2298 2288 } 2299 2289 … … 2365 2355 return false; 2366 2356 2357 /* XXX: Should lazily build a hash table in memory to index where keys are when 2358 * there are a large number of subkeys. Attach this to cached keys to 2359 * bound the extra amount of memory used. 2360 */ 2367 2361 for(i=0; (i < num_subkeys) && (found == false); i++) 2368 2362 { … … 2396 2390 bool found = false; 2397 2391 2392 /* XXX: Should lazily build a hash table in memory to index where values are when 2393 * there are a large number of them. Attach this to cached keys to 2394 * bound the extra amount of memory used. 2395 */ 2398 2396 for(i=0; (i < num_values) && (found == false); i++) 2399 2397 { … … 2494 2492 uint32_t type, REGFI_DATA* data) 2495 2493 { 2494 REGFI_BUFFER tmp_buf; 2496 2495 uint8_t** tmp_array; 2497 uint8_t* tmp_str; 2498 int32_t tmp_size; 2499 uint32_t i, j, array_size; 2496 uint32_t i, j; 2500 2497 2501 2498 if(data == NULL) … … 2508 2505 /* REG_LINK is a symbolic link, stored as a unicode string. */ 2509 2506 case REG_LINK: 2510 tmp_str = talloc_array(NULL, uint8_t, data->size); 2511 if(tmp_str == NULL) 2512 { 2507 tmp_buf = regfi_conv_charset(regfi_encoding_int2str(REGFI_ENCODING_UTF16LE), 2508 regfi_encoding_int2str(string_encoding), 2509 data->raw, data->size); 2510 if(tmp_buf.buf == NULL) 2511 { 2512 regfi_log_add(REGFI_LOG_INFO, "Error occurred while" 2513 " converting data of type %d to string encoding %d." 2514 " Error message: %s", 2515 type, string_encoding, strerror(errno)); 2513 2516 data->interpreted.string = NULL; 2514 2517 data->interpreted_size = 0; 2515 2518 return false; 2516 2519 } 2517 2518 tmp_size = regfi_conv_charset(regfi_encoding_int2str(REGFI_ENCODING_UTF16LE), 2519 regfi_encoding_int2str(string_encoding), 2520 data->raw, (char*)tmp_str, 2521 data->size, data->size); 2522 if(tmp_size < 0) 2523 { 2524 regfi_log_add(REGFI_LOG_INFO, "Error occurred while" 2525 " converting data of type %d to %d. Error message: %s", 2526 type, string_encoding, strerror(-tmp_size)); 2527 talloc_free(tmp_str); 2528 data->interpreted.string = NULL; 2529 data->interpreted_size = 0; 2530 return false; 2531 } 2532 2533 tmp_str = talloc_realloc(NULL, tmp_str, uint8_t, tmp_size); 2534 if(tmp_str == NULL) 2535 return false; 2536 data->interpreted.string = tmp_str; 2537 data->interpreted_size = tmp_size; 2538 talloc_reparent(NULL, data, tmp_str); 2520 2521 data->interpreted.string = tmp_buf.buf; 2522 data->interpreted_size = tmp_buf.len; 2523 talloc_reparent(NULL, data, tmp_buf.buf); 2539 2524 break; 2540 2525 … … 2574 2559 2575 2560 case REG_MULTI_SZ: 2576 tmp_str = talloc_array(NULL, uint8_t, data->size); 2577 if(tmp_str == NULL) 2578 { 2561 /* Attempt to convert entire string from UTF-16LE to output encoding, 2562 * then parse and quote fields individually. 2563 */ 2564 tmp_buf = regfi_conv_charset(regfi_encoding_int2str(REGFI_ENCODING_UTF16LE), 2565 regfi_encoding_int2str(string_encoding), 2566 data->raw, data->size); 2567 if(tmp_buf.buf == NULL) 2568 { 2569 regfi_log_add(REGFI_LOG_INFO, "Error occurred while" 2570 " converting data of type %d to string encoding %d." 2571 " Error message: %s", 2572 type, string_encoding, strerror(errno)); 2579 2573 data->interpreted.multiple_string = NULL; 2580 2574 data->interpreted_size = 0; … … 2582 2576 } 2583 2577 2584 /* Attempt to convert entire string from UTF-16LE to output encoding, 2585 * then parse and quote fields individually. 2586 */ 2587 tmp_size = regfi_conv_charset(regfi_encoding_int2str(REGFI_ENCODING_UTF16LE), 2588 regfi_encoding_int2str(string_encoding), 2589 data->raw, (char*)tmp_str, 2590 data->size, data->size); 2591 if(tmp_size < 0) 2592 { 2593 regfi_log_add(REGFI_LOG_INFO, "Error occurred while" 2594 " converting data of type %d to %s. Error message: %s", 2595 type, string_encoding, strerror(-tmp_size)); 2596 talloc_free(tmp_str); 2597 data->interpreted.multiple_string = NULL; 2598 data->interpreted_size = 0; 2599 return false; 2600 } 2601 2602 array_size = tmp_size+1; 2603 tmp_array = talloc_array(NULL, uint8_t*, array_size); 2578 tmp_array = talloc_array(NULL, uint8_t*, tmp_buf.len+1); 2604 2579 if(tmp_array == NULL) 2605 2580 { 2606 talloc_free(tmp_ str);2581 talloc_free(tmp_buf.buf); 2607 2582 data->interpreted.string = NULL; 2608 2583 data->interpreted_size = 0; 2609 2584 return false; 2610 2585 } 2611 2612 tmp_array[0] = tmp_str; 2613 for(i=0,j=1; i < tmp_size && j < array_size-1; i++) 2614 { 2615 if(tmp_str[i] == '\0' && (i+1 < tmp_size) && tmp_str[i+1] != '\0') 2616 tmp_array[j++] = tmp_str+i+1; 2586 2587 tmp_array[0] = tmp_buf.buf; 2588 for(i=0,j=1; i < tmp_buf.len && j < tmp_buf.len; i++) 2589 { 2590 if(tmp_buf.buf[i] == '\0' && (i+1 < tmp_buf.len) 2591 && tmp_buf.buf[i+1] != '\0') 2592 tmp_array[j++] = tmp_buf.buf+i+1; 2617 2593 } 2618 2594 tmp_array[j] = NULL; … … 2620 2596 data->interpreted.multiple_string = tmp_array; 2621 2597 /* XXX: how meaningful is this? should we store number of strings instead? */ 2622 data->interpreted_size = tmp_ size;2623 talloc_reparent(NULL, tmp_array, tmp_ str);2598 data->interpreted_size = tmp_buf.len; 2599 talloc_reparent(NULL, tmp_array, tmp_buf.buf); 2624 2600 talloc_reparent(NULL, data, tmp_array); 2625 2601 break; … … 2663 2639 2664 2640 /****************************************************************************** 2665 * Convert from UTF-16LE to specified character set.2666 * On error, returns a negative errno code.2641 * Convert string from input_charset to output_charset. 2642 * On error, returns a NULL buf attribute and sets the errno. 2667 2643 *****************************************************************************/ 2668 int32_t regfi_conv_charset(const char* input_charset, const char* output_charset, 2669 uint8_t* input, char* output, 2670 uint32_t input_len, uint32_t output_max) 2644 REGFI_BUFFER regfi_conv_charset(const char* input_charset, const char* output_charset, 2645 uint8_t* input, uint32_t input_len) 2671 2646 { 2672 2647 iconv_t conv_desc; 2673 2648 char* inbuf = (char*)input; 2674 char* outbuf = output; 2675 size_t in_len = (size_t)input_len; 2676 size_t out_len = (size_t)(output_max-1); 2649 char* outbuf; 2650 char* retbuf; 2651 size_t allocated = (size_t)input_len; 2652 size_t in_left = (size_t)input_len; 2653 size_t out_left = (size_t)allocated-1; 2654 REGFI_BUFFER ret_val; 2677 2655 int ret; 2678 2656 2657 ret_val.buf = NULL; 2658 ret_val.len = 0; 2659 retbuf = talloc_array(NULL, char, allocated); 2660 outbuf = retbuf; 2661 if(outbuf == NULL) 2662 { 2663 errno = ENOMEM; 2664 return ret_val; 2665 } 2666 2667 /* Set up conversion descriptor. */ 2679 2668 /* XXX: Consider creating a couple of conversion descriptors earlier, 2680 2669 * storing them on an iterator so they don't have to be recreated 2681 2670 * each time. 2682 2671 */ 2683 2684 /* Set up conversion descriptor. */2685 2672 conv_desc = iconv_open(output_charset, input_charset); 2686 2673 2687 ret = iconv(conv_desc, &inbuf, &in_len, &outbuf, &out_len); 2674 ret = 0; 2675 do 2676 { 2677 if(ret == -1) 2678 { 2679 retbuf = talloc_realloc(NULL, retbuf, char, allocated+(in_left*2)); 2680 if(retbuf == NULL) 2681 { 2682 errno = ENOMEM; 2683 return ret_val; 2684 } 2685 outbuf = retbuf+(allocated-1-out_left); 2686 out_left += in_left*2; 2687 allocated += in_left*2; 2688 } 2689 ret = iconv(conv_desc, &inbuf, &in_left, &outbuf, &out_left); 2690 2691 } while(ret == -1 && errno == E2BIG); 2692 2688 2693 if(ret == -1) 2689 2694 { 2690 2695 iconv_close(conv_desc); 2691 return -errno; 2692 } 2693 *outbuf = '\0'; 2694 2695 iconv_close(conv_desc); 2696 return output_max-out_len-1; 2697 } 2698 2696 return ret_val; 2697 } 2698 2699 /* Save memory */ 2700 if(out_left > 0) 2701 { 2702 retbuf = talloc_realloc(NULL, retbuf, char, allocated-out_left); 2703 if(retbuf == NULL) 2704 { 2705 errno = ENOMEM; 2706 return ret_val; 2707 } 2708 allocated -= out_left; 2709 } 2710 retbuf[allocated-1] = '\0'; 2711 iconv_close(conv_desc); 2712 2713 ret_val.buf = (uint8_t*)retbuf; 2714 ret_val.len = allocated-1; 2715 return ret_val; 2716 } 2699 2717 2700 2718 -
trunk/python/pyregfi/__init__.py
r261 r262 106 106 # @note Developers strive to make pyregfi thread-safe. 107 107 # 108 # @note Key and Value names are case-sensitive in regfi and pyregfi109 #110 108 import sys 111 109 import time … … 390 388 # 391 389 # @param name The name of the subkey or value desired. 392 # This is case-sensitive. 393 # 394 # @note The registry format does inherently prevent multiple 395 # subkeys or values from having the same name. 396 # This interface simply returns the first match. 390 # This is case-insensitive. 391 # 392 # @note The registry format does not inherently prevent multiple 393 # subkeys or values from having the same name, having a key 394 # and a value with the same name, or having the same name in 395 # different cases that could both match. 396 # This interface simply returns the first match in the list. 397 397 # Lookups using this method could also fail due to incorrectly 398 # encoded strings .399 # To identify any duplicates , use the iterator interface to400 # check every list element.398 # encoded strings stored as names. 399 # To identify any duplicates or elements with malformed names, 400 # use the iterator interface to check every list element. 401 401 # 402 402 # @return the first element whose name matches, or None if the element
Note: See TracChangeset
for help on using the changeset viewer.