3bbfaf24544bd5e3602dbab07013f49a95b2fa0f
[samba.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,
39                                               data.data, data.length,
40                                               (void **)&ret, NULL);
41                         break;
42                 case REG_DWORD:
43                 case REG_DWORD_BIG_ENDIAN:
44                         SMB_ASSERT(data.length == sizeof(uint32_t));
45                         ret = talloc_asprintf(mem_ctx, "0x%8.8x",
46                                               IVAL(data.data, 0));
47                         break;
48                 case REG_QWORD:
49                         SMB_ASSERT(data.length == sizeof(uint64_t));
50                         ret = talloc_asprintf(mem_ctx, "0x%16.16llx",
51                                               (long long)BVAL(data.data, 0));
52                         break;
53                 case REG_BINARY:
54                         ret = data_blob_hex_string_upper(mem_ctx, &data);
55                         break;
56                 case REG_NONE:
57                         /* "NULL" is the right return value */
58                         break;
59                 case REG_MULTI_SZ:
60                         /* FIXME: We don't support this yet */
61                         break;
62                 default:
63                         /* FIXME */
64                         /* Other datatypes aren't supported -> return "NULL" */
65                         break;
66         }
67
68         return ret;
69 }
70
71 /** Generate a string that describes a registry value */
72 _PUBLIC_ char *reg_val_description(TALLOC_CTX *mem_ctx,
73                                    const char *name,
74                                    uint32_t data_type,
75                                    const DATA_BLOB data)
76 {
77         return talloc_asprintf(mem_ctx, "%s = %s : %s", name?name:"<No Name>",
78                                str_regtype(data_type),
79                                reg_val_data_string(mem_ctx, data_type, data));
80 }
81
82 /*
83  * This implements reading hex bytes that include comma's.
84  * It was previously handled by strhex_to_data_blob, but that did not cover
85  * the format used by windows.
86  */
87 static DATA_BLOB reg_strhex_to_data_blob(TALLOC_CTX *mem_ctx, const char *str)
88 {
89         DATA_BLOB ret;
90         const char *HEXCHARS = "0123456789ABCDEF";
91         size_t i, j;
92         char *hi, *lo;
93
94         ret = data_blob_talloc_zero(mem_ctx, (strlen(str)+(strlen(str) % 3))/3);
95         j = 0;
96         for (i = 0; i < strlen(str); i++) {
97                 hi = strchr(HEXCHARS, toupper(str[i]));
98                 if (hi == NULL)
99                         continue;
100
101                 i++;
102                 lo = strchr(HEXCHARS, toupper(str[i]));
103                 if (lo == NULL)
104                         break;
105
106                 ret.data[j] = PTR_DIFF(hi, HEXCHARS) << 4;
107                 ret.data[j] += PTR_DIFF(lo, HEXCHARS);
108                 j++;
109
110                 if (j > ret.length) {
111                         DEBUG(0, ("Trouble converting hex string to bin\n"));
112                         break;
113                 }
114         }
115         return ret;
116 }
117
118
119 _PUBLIC_ bool reg_string_to_val(TALLOC_CTX *mem_ctx, const char *type_str,
120                                 const char *data_str, uint32_t *type, DATA_BLOB *data)
121 {
122         char *tmp_type_str, *p, *q;
123         int result;
124
125         *type = regtype_by_string(type_str);
126
127         if (*type == -1) {
128                 /* Normal windows format is hex, hex(type int as string),
129                    dword or just a string. */
130                 if (strncmp(type_str, "hex(", 4) == 0) {
131                         /* there is a hex string with the value type between
132                            the braces */
133                         tmp_type_str = talloc_strdup(mem_ctx, type_str);
134                         q = p = tmp_type_str + strlen("hex(");
135
136                         /* Go to the closing brace or end of the string */
137                         while (*q != ')' && *q != '\0') q++;
138                         *q = '\0';
139
140                         /* Convert hex string to int, store it in type */
141                         result = sscanf(p, "%x", type);
142                         if (!result) {
143                                 DEBUG(0, ("Could not convert hex to int\n"));
144                                 return false;
145                         }
146                         talloc_free(tmp_type_str);
147                 } else if (strcmp(type_str, "hex") == 0) {
148                         *type = REG_BINARY;
149                 } else if (strcmp(type_str, "dword") == 0) {
150                         *type = REG_DWORD;
151                 }
152         }
153
154         if (*type == -1)
155                 return false;
156
157         /* Convert data appropriately */
158
159         switch (*type) {
160                 case REG_SZ:
161                         return convert_string_talloc(mem_ctx,
162                                                      CH_UNIX, CH_UTF16,
163                                                      data_str, strlen(data_str)+1,
164                                                      (void **)&data->data,
165                                                      &data->length);
166                         break;
167                 case REG_MULTI_SZ:
168                 case REG_EXPAND_SZ:
169                 case REG_BINARY:
170                         *data = reg_strhex_to_data_blob(mem_ctx, data_str);
171                         break;
172                 case REG_DWORD:
173                 case REG_DWORD_BIG_ENDIAN: {
174                         uint32_t tmp = strtol(data_str, NULL, 16);
175                         *data = data_blob_talloc(mem_ctx, NULL, sizeof(uint32_t));
176                         if (data->data == NULL) return false;
177                         SIVAL(data->data, 0, tmp);
178                         }
179                         break;
180                 case REG_QWORD: {
181                         uint64_t tmp = strtoll(data_str, NULL, 16);
182                         *data = data_blob_talloc(mem_ctx, NULL, sizeof(uint64_t));
183                         if (data->data == NULL) return false;
184                         SBVAL(data->data, 0, tmp);
185                         }
186                         break;
187                 case REG_NONE:
188                         ZERO_STRUCTP(data);
189                         break;
190                 default:
191                         /* FIXME */
192                         /* Other datatypes aren't supported -> return no success */
193                         return false;
194         }
195         return true;
196 }
197
198 /** Open a key by name (including the predefined key name!) */
199 WERROR reg_open_key_abs(TALLOC_CTX *mem_ctx, struct registry_context *handle,
200                         const char *name, struct registry_key **result)
201 {
202         struct registry_key *predef;
203         WERROR error;
204         size_t predeflength;
205         char *predefname;
206
207         if (strchr(name, '\\') != NULL)
208                 predeflength = strchr(name, '\\')-name;
209         else
210                 predeflength = strlen(name);
211
212         predefname = talloc_strndup(mem_ctx, name, predeflength);
213         W_ERROR_HAVE_NO_MEMORY(predefname);
214         error = reg_get_predefined_key_by_name(handle, predefname, &predef);
215         talloc_free(predefname);
216
217         if (!W_ERROR_IS_OK(error)) {
218                 return error;
219         }
220
221         if (strchr(name, '\\')) {
222                 return reg_open_key(mem_ctx, predef, strchr(name, '\\')+1,
223                                     result);
224         } else {
225                 *result = predef;
226                 return WERR_OK;
227         }
228 }
229
230 static WERROR get_abs_parent(TALLOC_CTX *mem_ctx, struct registry_context *ctx,
231                              const char *path, struct registry_key **parent,
232                              const char **name)
233 {
234         char *parent_name;
235         WERROR error;
236
237         if (strchr(path, '\\') == NULL) {
238                 return WERR_FOOBAR;
239         }
240
241         parent_name = talloc_strndup(mem_ctx, path, strrchr(path, '\\')-path);
242         W_ERROR_HAVE_NO_MEMORY(parent_name);
243         error = reg_open_key_abs(mem_ctx, ctx, parent_name, parent);
244         talloc_free(parent_name);
245         if (!W_ERROR_IS_OK(error)) {
246                 return error;
247         }
248
249         *name = talloc_strdup(mem_ctx, strrchr(path, '\\')+1);
250         W_ERROR_HAVE_NO_MEMORY(*name);
251
252         return WERR_OK;
253 }
254
255 WERROR reg_key_del_abs(struct registry_context *ctx, const char *path)
256 {
257         struct registry_key *parent;
258         const char *n;
259         TALLOC_CTX *mem_ctx = talloc_init("reg_key_del_abs");
260         WERROR error;
261
262         if (!strchr(path, '\\')) {
263                 return WERR_FOOBAR;
264         }
265
266         error = get_abs_parent(mem_ctx, ctx, path, &parent, &n);
267         if (W_ERROR_IS_OK(error)) {
268                 error = reg_key_del(mem_ctx, parent, n);
269         }
270
271         talloc_free(mem_ctx);
272
273         return error;
274 }
275
276 WERROR reg_key_add_abs(TALLOC_CTX *mem_ctx, struct registry_context *ctx,
277                        const char *path, uint32_t access_mask,
278                        struct security_descriptor *sec_desc,
279                        struct registry_key **result)
280 {
281         struct registry_key *parent;
282         const char *n;
283         WERROR error;
284
285         *result = NULL;
286
287         if (!strchr(path, '\\')) {
288                 return WERR_ALREADY_EXISTS;
289         }
290
291         error = get_abs_parent(mem_ctx, ctx, path, &parent, &n);
292         if (!W_ERROR_IS_OK(error)) {
293                 DEBUG(2, ("Opening parent of %s failed with %s\n", path,
294                                   win_errstr(error)));
295                 return error;
296         }
297
298         error = reg_key_add_name(mem_ctx, parent, n, NULL, sec_desc, result);
299
300         return error;
301 }