d1e953951fccd3914cb2c4147da9100db5f70eb7
[ira/wip.git] / source4 / lib / registry / util.c
1 /*
2    Unix SMB/CIFS implementation.
3    Transparent registry backend handling
4    Copyright (C) Jelmer Vernooij                        2003-2007.
5    Copyright (C) Wilco Baan Hofman                      2010.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "lib/registry/registry.h"
23 #include "librpc/gen_ndr/winreg.h"
24 #include "lib/util/data_blob.h"
25
26 _PUBLIC_ char *reg_val_data_string(TALLOC_CTX *mem_ctx, uint32_t type,
27                                    const DATA_BLOB data)
28 {
29         char *ret = NULL;
30
31         if (data.length == 0)
32                 return talloc_strdup(mem_ctx, "");
33
34         switch (type) {
35                 case REG_EXPAND_SZ:
36                 case REG_SZ:
37                         convert_string_talloc(mem_ctx,
38                                                           CH_UTF16, CH_UNIX, data.data, data.length,
39                                                           (void **)&ret, NULL, false);
40                         break;
41                 case REG_DWORD:
42                 case REG_DWORD_BIG_ENDIAN:
43                         SMB_ASSERT(data.length == sizeof(uint32_t));
44                         ret = talloc_asprintf(mem_ctx, "0x%8.8x",
45                                               IVAL(data.data, 0));
46                         break;
47                 case REG_QWORD:
48                         SMB_ASSERT(data.length == sizeof(uint64_t));
49                         ret = talloc_asprintf(mem_ctx, "0x%16.16llx",
50                                               (long long)BVAL(data.data, 0));
51                         break;
52                 case REG_BINARY:
53                         ret = data_blob_hex_string_upper(mem_ctx, &data);
54                         break;
55                 case REG_NONE:
56                         /* "NULL" is the right return value */
57                         break;
58                 case REG_MULTI_SZ:
59                         /* FIXME: We don't support this yet */
60                         break;
61                 default:
62                         /* FIXME */
63                         /* Other datatypes aren't supported -> return "NULL" */
64                         break;
65         }
66
67         return ret;
68 }
69
70 /** Generate a string that describes a registry value */
71 _PUBLIC_ char *reg_val_description(TALLOC_CTX *mem_ctx, 
72                                    const char *name,
73                                    uint32_t data_type,
74                                    const DATA_BLOB data)
75 {
76         return talloc_asprintf(mem_ctx, "%s = %s : %s", name?name:"<No Name>",
77                                str_regtype(data_type),
78                                reg_val_data_string(mem_ctx, data_type, data));
79 }
80
81 /*
82  * This implements reading hex bytes that include comma's.
83  * It was previously handled by strhex_to_data_blob, but that did not cover 
84  * the format used by windows.
85  */
86 static DATA_BLOB reg_strhex_to_data_blob(TALLOC_CTX *mem_ctx, const char *str)
87 {
88         DATA_BLOB ret;
89         const char *HEXCHARS = "0123456789ABCDEF";
90         size_t i, j;
91         char *hi, *lo;
92
93         ret = data_blob_talloc_zero(mem_ctx, (strlen(str)+(strlen(str) % 3))/3);
94         j = 0;
95         for (i = 0; i < strlen(str); i++) {
96                 hi = strchr(HEXCHARS, toupper(str[i]));
97                 if (hi == NULL)
98                         continue;
99
100                 i++;
101                 lo = strchr(HEXCHARS, toupper(str[i]));
102                 if (lo == NULL)
103                         break;
104                 
105                 ret.data[j] = PTR_DIFF(hi, HEXCHARS) << 4;
106                 ret.data[j] += PTR_DIFF(lo, HEXCHARS);
107                 j++;
108
109                 if (j > ret.length) {
110                         DEBUG(0, ("Trouble converting hex string to bin\n"));
111                         break;
112                 }
113         }
114         return ret;
115
116
117
118 _PUBLIC_ bool reg_string_to_val(TALLOC_CTX *mem_ctx, const char *type_str,
119                                 const char *data_str, uint32_t *type, DATA_BLOB *data)
120 {
121         char *tmp_type_str, *p, *q;
122         int result;
123
124         *type = regtype_by_string(type_str);
125
126         if (*type == -1) {
127                 /* Normal windows format is hex, hex(type int as string),
128                    dword or just a string. */
129                 if (strncmp(type_str, "hex(", 4) == 0) {
130                         /* there is a hex string with the value type between
131                            the braces */
132                         tmp_type_str = talloc_strdup(mem_ctx, type_str);
133                         q = p = tmp_type_str + strlen("hex(");
134
135                         /* Go to the closing brace or end of the string */
136                         while (*q != ')' && *q != '\0') q++;
137                         *q = '\0';
138
139                         /* Convert hex string to int, store it in type */
140                         result = sscanf(p, "%x", type);
141                         if (!result) {
142                                 DEBUG(0, ("Could not convert hex to int\n"));
143                                 return false;
144                         }
145                         talloc_free(tmp_type_str);
146                 } else if (strcmp(type_str, "hex") == 0) {
147                         *type = REG_BINARY;
148                 } else if (strcmp(type_str, "dword") == 0) {
149                         *type = REG_DWORD;
150                 }
151         }
152
153         if (*type == -1)
154                 return false;
155
156         /* Convert data appropriately */
157
158         switch (*type) {
159                 case REG_SZ:
160                         return convert_string_talloc(mem_ctx,
161                                                                  CH_UNIX, CH_UTF16, data_str,
162                                                                  strlen(data_str)+1,
163                                                                  (void **)&data->data,
164                                                                  &data->length, false);
165                         break;
166                 case REG_MULTI_SZ:
167                 case REG_EXPAND_SZ:
168                 case REG_BINARY:
169                         *data = reg_strhex_to_data_blob(mem_ctx, data_str);
170                         break;
171                 case REG_DWORD:
172                 case REG_DWORD_BIG_ENDIAN: {
173                         uint32_t tmp = strtol(data_str, NULL, 16);
174                         *data = data_blob_talloc(mem_ctx, NULL, sizeof(uint32_t));
175                         if (data->data == NULL) return false;
176                         SIVAL(data->data, 0, tmp);
177                         }
178                         break;
179                 case REG_QWORD: {
180                         uint64_t tmp = strtoll(data_str, NULL, 0);
181                         *data = data_blob_talloc(mem_ctx, NULL, sizeof(uint64_t));
182                         if (data->data == NULL) return false;
183                         SBVAL(data->data, 0, tmp);
184                         }
185                         break;
186                 case REG_NONE:
187                         ZERO_STRUCTP(data);
188                         break;
189                 default:
190                         /* FIXME */
191                         /* Other datatypes aren't supported -> return no success */
192                         return false;
193         }
194         return true;
195 }
196
197 /** Open a key by name (including the predefined key name!) */
198 WERROR reg_open_key_abs(TALLOC_CTX *mem_ctx, struct registry_context *handle,
199                         const char *name, struct registry_key **result)
200 {
201         struct registry_key *predef;
202         WERROR error;
203         size_t predeflength;
204         char *predefname;
205
206         if (strchr(name, '\\') != NULL)
207                 predeflength = strchr(name, '\\')-name;
208         else
209                 predeflength = strlen(name);
210
211         predefname = talloc_strndup(mem_ctx, name, predeflength);
212         W_ERROR_HAVE_NO_MEMORY(predefname);
213         error = reg_get_predefined_key_by_name(handle, predefname, &predef);
214         talloc_free(predefname);
215
216         if (!W_ERROR_IS_OK(error)) {
217                 return error;
218         }
219
220         if (strchr(name, '\\')) {
221                 return reg_open_key(mem_ctx, predef, strchr(name, '\\')+1,
222                                     result);
223         } else {
224                 *result = predef;
225                 return WERR_OK;
226         }
227 }
228
229 static WERROR get_abs_parent(TALLOC_CTX *mem_ctx, struct registry_context *ctx,
230                              const char *path, struct registry_key **parent,
231                              const char **name)
232 {
233         char *parent_name;
234         WERROR error;
235
236         if (strchr(path, '\\') == NULL) {
237                 return WERR_FOOBAR;
238         }
239
240         parent_name = talloc_strndup(mem_ctx, path, strrchr(path, '\\')-path);
241         W_ERROR_HAVE_NO_MEMORY(parent_name);
242         error = reg_open_key_abs(mem_ctx, ctx, parent_name, parent);
243         talloc_free(parent_name);
244         if (!W_ERROR_IS_OK(error)) {
245                 return error;
246         }
247
248         *name = talloc_strdup(mem_ctx, strrchr(path, '\\')+1);
249         W_ERROR_HAVE_NO_MEMORY(*name);
250
251         return WERR_OK;
252 }
253
254 WERROR reg_key_del_abs(struct registry_context *ctx, const char *path)
255 {
256         struct registry_key *parent;
257         const char *n;
258         TALLOC_CTX *mem_ctx = talloc_init("reg_key_del_abs");
259         WERROR error;
260
261         if (!strchr(path, '\\')) {
262                 return WERR_FOOBAR;
263         }
264
265         error = get_abs_parent(mem_ctx, ctx, path, &parent, &n);
266         if (W_ERROR_IS_OK(error)) {
267                 error = reg_key_del(mem_ctx, parent, n);
268         }
269
270         talloc_free(mem_ctx);
271
272         return error;
273 }
274
275 WERROR reg_key_add_abs(TALLOC_CTX *mem_ctx, struct registry_context *ctx,
276                        const char *path, uint32_t access_mask,
277                        struct security_descriptor *sec_desc,
278                        struct registry_key **result)
279 {
280         struct registry_key *parent;
281         const char *n;
282         WERROR error;
283
284         *result = NULL;
285
286         if (!strchr(path, '\\')) {
287                 return WERR_ALREADY_EXISTS;
288         }
289
290         error = get_abs_parent(mem_ctx, ctx, path, &parent, &n);
291         if (!W_ERROR_IS_OK(error)) {
292                 DEBUG(2, ("Opening parent of %s failed with %s\n", path,
293                                   win_errstr(error)));
294                 return error;
295         }
296
297         error = reg_key_add_name(mem_ctx, parent, n, NULL, sec_desc, result);
298
299         return error;
300 }