winprefs v0.3.2
A registry exporter for programmers.
Loading...
Searching...
No Matches
reg_command.c
1#include "reg_command.h"
2#include "constants.h"
3#include "io.h"
4#include "registry.h"
5#include "shell.h"
6
7static wchar_t *REG_PARAM_SLASH_VE = L"/ve ";
8
9wchar_t *fix_v_param(const wchar_t *prop, size_t prop_len, bool *heap) {
10 wchar_t *escaped, *out;
11 escaped = out = nullptr;
12 *heap = true;
13 if (prop_len == 0 || prop == nullptr || !wcsncmp(L"(default)", prop, 9)) {
14 *heap = false;
15 out = REG_PARAM_SLASH_VE;
16 goto cleanup;
17 }
18 escaped = escape_for_batch(prop, prop_len);
19 size_t escaped_len = (7 + wcslen(escaped)) * WL;
20 out = calloc(7 + wcslen(escaped), WL);
21 if (!out) { // LCOV_EXCL_START
22 goto fail;
23 } // LCOV_EXCL_STOP
24 memset(out, 0, escaped_len);
25 _snwprintf(out, escaped_len, L"/v \"%ls\" ", escaped);
26 goto cleanup;
27fail: // LCOV_EXCL_START
28 out = nullptr;
29 // LCOV_EXCL_STOP
30cleanup:
31 free(escaped);
32 return out;
33}
34
35wchar_t *convert_data_for_reg(DWORD reg_type, const char *data, size_t data_len) {
36 wchar_t *bin, *out, *s;
37 bin = out = s = nullptr;
38 if (reg_type == REG_BINARY) {
39 size_t i;
40 size_t n_bin_chars = 2 * data_len;
41 size_t new_len = n_bin_chars + 1;
42 bin = calloc(new_len, WL);
43 if (!bin) { // LCOV_EXCL_START
44 goto fail;
45 } // LCOV_EXCL_STOP
46 wmemset(bin, L'\0', new_len);
47 for (i = 0; i < data_len; i++) {
48 wchar_t conv[3];
49 _snwprintf(conv, 3, L"%02x", data[i]);
50 conv[2] = L'\0';
51 wcsncat(&bin[i], conv, 2);
52 }
53 size_t s_size = new_len + 5;
54 out = calloc(s_size, WL);
55 if (!out) { // LCOV_EXCL_START
56 goto fail;
57 } // LCOV_EXCL_STOP
58 wmemset(out, L'\0', s_size);
59 _snwprintf(out, s_size, L" /d %ls ", bin);
60 goto cleanup;
61 }
62 if (reg_type == REG_EXPAND_SZ || reg_type == REG_SZ || reg_type == REG_MULTI_SZ) {
63 size_t w_data_len = ((data_len % WL == 0) ? data_len / WL : (data_len / WL) + 1);
64 wchar_t *w_data = (wchar_t *)data;
65 size_t real_len = reg_type == REG_MULTI_SZ ? determine_multi_sz_size(w_data, w_data_len) : wcslen(w_data);
66 if (reg_type == REG_MULTI_SZ && real_len <= 2) {
67 goto fail;
68 }
69 s = escape_for_batch((wchar_t *)data, real_len);
70 if (!unlikely(s)) { // LCOV_EXCL_START
71 goto fail;
72 } // LCOV_EXCL_STOP
73 size_t s_size = (wcslen(s) + 8);
74 out = calloc(s_size, WL);
75 if (!unlikely(out)) { // LCOV_EXCL_START
76 goto fail;
77 } // LCOV_EXCL_STOP
78 wmemset(out, L'\0', s_size);
79 _snwprintf(out, s_size, L" /d \"%ls\" ", s);
80 goto cleanup;
81 }
82 if (reg_type == REG_DWORD || reg_type == REG_QWORD) {
83 size_t s_size = 128;
84 out = calloc(s_size, WL);
85 if (!out) { // LCOV_EXCL_START
86 goto fail;
87 } // LCOV_EXCL_STOP
88 memset(out, 0, s_size);
89 if (reg_type == REG_DWORD) {
90 _snwprintf(out, s_size, L" /d %lu ", *(DWORD *)data);
91 } else {
92 _snwprintf(out, s_size, L" /d %llu ", *(UINT64 *)data);
93 }
94 goto cleanup;
95 }
96 errno = EINVAL;
97fail:
98 out = nullptr;
99cleanup:
100 free(bin);
101 free(s);
102 return out;
103}
104
105bool do_write_reg_command(writer_t *writer,
106 const wchar_t *full_path,
107 const wchar_t *prop,
108 const char *value,
109 size_t data_len,
110 unsigned long type) {
111 bool ret = true;
112 wchar_t *out = nullptr;
113 wchar_t *escaped_d = convert_data_for_reg(type, value, data_len);
114 wchar_t *escaped_reg_key = escape_for_batch(full_path, wcslen(full_path));
115 bool v_heap = false;
116 wchar_t *v_param = fix_v_param(prop, prop ? wcslen(prop) : 0, &v_heap);
117 wchar_t reg_type[14];
118 if (!escaped_reg_key || !v_param) { // LCOV_EXCL_START
119 goto fail;
120 } // LCOV_EXCL_STOP
121 if (type == REG_MULTI_SZ && !escaped_d) {
122 goto cleanup;
123 }
124 wmemset(reg_type, L'\0', 14);
125 switch (type) {
126 case REG_NONE:
127 wcsncpy(reg_type, L"REG_NONE", 8);
128 break;
129 case REG_BINARY:
130 wcsncpy(reg_type, L"REG_BINARY", 10);
131 break;
132 case REG_SZ:
133 wcsncpy(reg_type, L"REG_SZ", 6);
134 break;
135 case REG_EXPAND_SZ:
136 wcsncpy(reg_type, L"REG_EXPAND_SZ", 13);
137 break;
138 case REG_MULTI_SZ:
139 wcsncpy(reg_type, L"REG_MULTI_SZ", 12);
140 break;
141 case REG_DWORD:
142 wcsncpy(reg_type, L"REG_DWORD", 9);
143 break;
144 case REG_QWORD:
145 wcsncpy(reg_type, L"REG_QWORD", 9);
146 break;
147 default:
148 debug_print(L"Invalid registry data type.\n");
149 goto cleanup;
150 }
151 int req_size = _snwprintf(nullptr,
152 0,
153 L"reg add \"%ls\" %ls/t %ls%ls/f",
154 escaped_reg_key,
155 v_param,
156 reg_type,
157 escaped_d ? escaped_d : L" ");
158 if (req_size >= 1 && (size_t)req_size < CMD_MAX_COMMAND_LENGTH) {
159 size_t total_size = (size_t)req_size + 1;
160 out = calloc(total_size, WL);
161 if (!out) { // LCOV_EXCL_START
162 goto fail;
163 } // LCOV_EXCL_STOP
164 wmemset(out, L'\0', total_size);
165 int wrote = _snwprintf(out,
166 total_size,
167 L"reg add \"%ls\" %ls/t %ls%ls/f",
168 escaped_reg_key,
169 v_param,
170 reg_type,
171 escaped_d ? escaped_d : L" ");
172 if (wrote) {
173 ret = write_output(out, true, writer);
174 }
175 } else {
176 errno = EKEYREJECTED;
177 debug_print(L"%ls %ls: Skipping due to length of command.\n", full_path, prop);
178 }
179 goto cleanup;
180fail:
181 ret = false;
182cleanup:
183 free(escaped_d);
184 if (v_heap) {
185 free(v_param);
186 }
187 free(out);
188 free(escaped_reg_key);
189 return ret;
190}