r20037: Reduce code size slightly by shuffling stuff around
[kai/samba.git] / source3 / registry / reg_api.c
1 /* 
2  *  Unix SMB/CIFS implementation.
3  *  Virtual Windows Registry Layer
4  *  Copyright (C) Volker Lendecke 2006
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *  
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *  
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 /* Attempt to wrap the existing API in a more winreg.idl-like way */
22
23 #include "includes.h"
24
25 static WERROR fill_value_cache(struct registry_key *key)
26 {
27         if (key->values != NULL) {
28                 return WERR_OK;
29         }
30
31         if (!(key->values = TALLOC_ZERO_P(key, REGVAL_CTR))) {
32                 return WERR_NOMEM;
33         }
34         if (fetch_reg_values(key->key, key->values) == -1) {
35                 TALLOC_FREE(key->values);
36                 return WERR_BADFILE;
37         }
38
39         return WERR_OK;
40 }
41
42 static WERROR fill_subkey_cache(struct registry_key *key)
43 {
44         if (key->subkeys != NULL) {
45                 return WERR_OK;
46         }
47
48         if (!(key->subkeys = TALLOC_ZERO_P(key, REGSUBKEY_CTR))) {
49                 return WERR_NOMEM;
50         }
51
52         if (fetch_reg_keys(key->key, key->subkeys) == -1) {
53                 TALLOC_FREE(key->subkeys);
54                 return WERR_NO_MORE_ITEMS;
55         }
56
57         return WERR_OK;
58 }
59
60 WERROR reg_openhive(TALLOC_CTX *mem_ctx, const char *hive,
61                     uint32 desired_access,
62                     const struct nt_user_token *token,
63                     struct registry_key **pkey)
64 {
65         SMB_ASSERT(hive != NULL);
66         SMB_ASSERT(hive[0] != '\0');
67         SMB_ASSERT(strchr(hive, '\\') == NULL);
68
69         return regkey_open_onelevel(mem_ctx, NULL, hive, token, desired_access,
70                                     pkey);
71 }
72
73 WERROR reg_openkey(TALLOC_CTX *mem_ctx, struct registry_key *parent,
74                    const char *name, uint32 desired_access,
75                    struct registry_key **pkey)
76 {
77         struct registry_key *direct_parent = parent;
78         WERROR err;
79         char *p, *path, *to_free;
80         size_t len;
81
82         if (!(path = SMB_STRDUP(name))) {
83                 return WERR_NOMEM;
84         }
85         to_free = path;
86
87         len = strlen(path);
88
89         if ((len > 0) && (path[len-1] == '\\')) {
90                 path[len-1] = '\0';
91         }
92
93         while ((p = strchr(path, '\\')) != NULL) {
94                 char *name_component;
95                 struct registry_key *tmp;
96
97                 if (!(name_component = SMB_STRNDUP(path, (p - path)))) {
98                         err = WERR_NOMEM;
99                         goto error;
100                 }
101
102                 err = regkey_open_onelevel(mem_ctx, direct_parent,
103                                            name_component, parent->token,
104                                            SEC_RIGHTS_ENUM_SUBKEYS, &tmp);
105                 SAFE_FREE(name_component);
106
107                 if (!W_ERROR_IS_OK(err)) {
108                         goto error;
109                 }
110                 if (direct_parent != parent) {
111                         TALLOC_FREE(direct_parent);
112                 }
113
114                 direct_parent = tmp;
115                 path = p+1;
116         }
117
118         err = regkey_open_onelevel(mem_ctx, direct_parent, path, parent->token,
119                                    desired_access, pkey);
120  error:
121         if (direct_parent != parent) {
122                 TALLOC_FREE(direct_parent);
123         }
124         SAFE_FREE(to_free);
125         return err;
126 }
127
128 WERROR reg_enumkey(TALLOC_CTX *mem_ctx, struct registry_key *key,
129                    uint32 idx, char **name, NTTIME *last_write_time)
130 {
131         WERROR err;
132
133         if (!(key->key->access_granted & SEC_RIGHTS_ENUM_SUBKEYS)) {
134                 return WERR_ACCESS_DENIED;
135         }
136
137         if (!W_ERROR_IS_OK(err = fill_subkey_cache(key))) {
138                 return err;
139         }
140
141         if (idx >= key->subkeys->num_subkeys) {
142                 return WERR_NO_MORE_ITEMS;
143         }
144
145         if (!(*name = talloc_strdup(mem_ctx, key->subkeys->subkeys[idx]))) {
146                 return WERR_NOMEM;
147         }
148
149         if (last_write_time) {
150                 *last_write_time = 0;
151         }
152
153         return WERR_OK;
154 }
155
156 WERROR reg_enumvalue(TALLOC_CTX *mem_ctx, struct registry_key *key,
157                      uint32 idx, char **pname, struct registry_value **pval)
158 {
159         struct registry_value *val;
160         WERROR err;
161
162         if (!(key->key->access_granted & SEC_RIGHTS_QUERY_VALUE)) {
163                 return WERR_ACCESS_DENIED;
164         }
165
166         if (!(W_ERROR_IS_OK(err = fill_value_cache(key)))) {
167                 return err;
168         }
169
170         if (idx >= key->values->num_values) {
171                 return WERR_BADFILE;
172         }
173
174         err = registry_pull_value(mem_ctx, &val,
175                                   key->values->values[idx]->type,
176                                   key->values->values[idx]->data_p,
177                                   key->values->values[idx]->size,
178                                   key->values->values[idx]->size);
179         if (!W_ERROR_IS_OK(err)) {
180                 return err;
181         }
182
183         if (pname
184             && !(*pname = talloc_strdup(
185                          mem_ctx, key->values->values[idx]->valuename))) {
186                 SAFE_FREE(val);
187                 return WERR_NOMEM;
188         }
189                 
190         *pval = val;
191         return WERR_OK;
192 }
193
194 WERROR reg_queryvalue(TALLOC_CTX *mem_ctx, struct registry_key *key,
195                       const char *name, struct registry_value **pval)
196 {
197         WERROR err;
198         uint32 i;
199
200         if (!(key->key->access_granted & SEC_RIGHTS_QUERY_VALUE)) {
201                 return WERR_ACCESS_DENIED;
202         }
203
204         if (!(W_ERROR_IS_OK(err = fill_value_cache(key)))) {
205                 return err;
206         }
207
208         for (i=0; i<key->values->num_values; i++) {
209                 if (strequal(key->values->values[i]->valuename, name)) {
210                         return reg_enumvalue(mem_ctx, key, i, NULL, pval);
211                 }
212         }
213
214         return WERR_BADFILE;
215 }
216
217 WERROR reg_queryinfokey(struct registry_key *key, uint32_t *num_subkeys,
218                         uint32_t *max_subkeylen, uint32_t *max_subkeysize, 
219                         uint32_t *num_values, uint32_t *max_valnamelen, 
220                         uint32_t *max_valbufsize, uint32_t *secdescsize,
221                         NTTIME *last_changed_time)
222 {
223         uint32 i, max_size;
224         size_t max_len;
225         TALLOC_CTX *mem_ctx;
226         WERROR err;
227         struct security_descriptor *secdesc;
228
229         if (!(key->key->access_granted & SEC_RIGHTS_QUERY_VALUE)) {
230                 return WERR_ACCESS_DENIED;
231         }
232
233         if (!W_ERROR_IS_OK(fill_subkey_cache(key)) ||
234             !W_ERROR_IS_OK(fill_value_cache(key))) {
235                 return WERR_BADFILE;
236         }
237
238         max_len = 0;
239         for (i=0; i<key->subkeys->num_subkeys; i++) {
240                 max_len = MAX(max_len, strlen(key->subkeys->subkeys[i]));
241         }
242
243         *num_subkeys = key->subkeys->num_subkeys;
244         *max_subkeylen = max_len;
245         *max_subkeysize = 0;    /* Class length? */
246
247         max_len = 0;
248         max_size = 0;
249         for (i=0; i<key->values->num_values; i++) {
250                 max_len = MAX(max_len,
251                               strlen(key->values->values[i]->valuename));
252                 max_size = MAX(max_size, key->values->values[i]->size);
253         }
254
255         *num_values = key->values->num_values;
256         *max_valnamelen = max_len;
257         *max_valbufsize = max_size;
258
259         if (!(mem_ctx = talloc_new(key))) {
260                 return WERR_NOMEM;
261         }
262
263         err = regkey_get_secdesc(mem_ctx, key->key, &secdesc);
264         if (!W_ERROR_IS_OK(err)) {
265                 TALLOC_FREE(mem_ctx);
266                 return err;
267         }
268
269         *secdescsize = sec_desc_size(secdesc);
270         TALLOC_FREE(mem_ctx);
271
272         *last_changed_time = 0;
273
274         return WERR_OK;
275 }
276
277 WERROR reg_createkey(TALLOC_CTX *ctx, struct registry_key *parent,
278                      const char *subkeypath, uint32 desired_access,
279                      struct registry_key **pkey,
280                      enum winreg_CreateAction *paction)
281 {
282         struct registry_key *key = parent;
283         struct registry_key *create_parent;
284         TALLOC_CTX *mem_ctx;
285         char *path, *end;
286         WERROR err;
287         REGSUBKEY_CTR *subkeys;
288
289         if (!(mem_ctx = talloc_new(ctx))) return WERR_NOMEM;
290
291         if (!(path = talloc_strdup(mem_ctx, subkeypath))) {
292                 err = WERR_NOMEM;
293                 goto done;
294         }
295
296         while ((end = strchr(path, '\\')) != NULL) {
297                 struct registry_key *tmp;
298                 enum winreg_CreateAction action;
299
300                 *end = '\0';
301
302                 err = reg_createkey(mem_ctx, key, path,
303                                     SEC_RIGHTS_ENUM_SUBKEYS, &tmp, &action);
304                 if (!W_ERROR_IS_OK(err)) {
305                         goto done;
306                 }
307
308                 if (key != parent) {
309                         TALLOC_FREE(key);
310                 }
311
312                 key = tmp;
313                 path = end+1;
314         }
315
316         /*
317          * At this point, "path" contains the one-element subkey of "key". We
318          * can try to open it.
319          */
320
321         err = reg_openkey(ctx, key, path, desired_access, pkey);
322         if (W_ERROR_IS_OK(err)) {
323                 if (paction != NULL) {
324                         *paction = REG_OPENED_EXISTING_KEY;
325                 }
326                 goto done;
327         }
328
329         if (!W_ERROR_EQUAL(err, WERR_BADFILE)) {
330                 /*
331                  * Something but "notfound" has happened, so bail out
332                  */
333                 goto done;
334         }
335
336         /*
337          * We have to make a copy of the current key, as we opened it only
338          * with ENUM_SUBKEY access.
339          */
340
341         err = reg_openkey(mem_ctx, key, "", SEC_RIGHTS_CREATE_SUBKEY,
342                           &create_parent);
343         if (!W_ERROR_IS_OK(err)) {
344                 goto done;
345         }
346
347         /*
348          * Actually create the subkey
349          */
350
351         if (!(subkeys = TALLOC_ZERO_P(mem_ctx, REGSUBKEY_CTR))) {
352                 err = WERR_NOMEM;
353                 goto done;
354         }
355
356         err = fill_subkey_cache(create_parent);
357         if (!W_ERROR_IS_OK(err)) goto done;
358
359         err = regsubkey_ctr_addkey(create_parent->subkeys, path);
360         if (!W_ERROR_IS_OK(err)) goto done;
361
362         if (!store_reg_keys(create_parent->key, create_parent->subkeys)) {
363                 TALLOC_FREE(create_parent->subkeys);
364                 err = WERR_REG_IO_FAILURE;
365                 goto done;
366         }
367
368         /*
369          * Now open the newly created key
370          */
371
372         err = reg_openkey(ctx, create_parent, path, desired_access, pkey);
373         if (W_ERROR_IS_OK(err) && (paction != NULL)) {
374                 *paction = REG_CREATED_NEW_KEY;
375         }
376
377  done:
378         TALLOC_FREE(mem_ctx);
379         return err;
380 }
381                      
382
383 WERROR reg_deletekey(struct registry_key *parent, const char *path)
384 {
385         WERROR err;
386         TALLOC_CTX *mem_ctx;
387         char *name, *end;
388         int num_subkeys;
389
390         if (!(mem_ctx = talloc_init("reg_createkey"))) return WERR_NOMEM;
391
392         if (!(name = talloc_strdup(mem_ctx, path))) {
393                 err = WERR_NOMEM;
394                 goto error;
395         }
396
397         if ((end = strrchr(name, '\\')) != NULL) {
398                 struct registry_key *tmp;
399
400                 *end = '\0';
401
402                 err = reg_openkey(mem_ctx, parent, name,
403                                   SEC_RIGHTS_CREATE_SUBKEY, &tmp);
404                 if (!W_ERROR_IS_OK(err)) {
405                         goto error;
406                 }
407
408                 parent = tmp;
409                 name = end+1;
410         }
411
412         if (name[0] == '\0') {
413                 err = WERR_INVALID_PARAM;
414                 goto error;
415         }
416
417         if (!W_ERROR_IS_OK(err = fill_subkey_cache(parent))) {
418                 goto error;
419         }
420
421         num_subkeys = parent->subkeys->num_subkeys;
422
423         if (regsubkey_ctr_delkey(parent->subkeys, name) == num_subkeys) {
424                 err = WERR_BADFILE;
425                 goto error;
426         }
427
428         if (!store_reg_keys(parent->key, parent->subkeys)) {
429                 TALLOC_FREE(parent->subkeys);
430                 err = WERR_REG_IO_FAILURE;
431                 goto error;
432         }
433
434         err = WERR_OK;
435  error:
436         TALLOC_FREE(mem_ctx);
437         return err;
438 }
439
440 WERROR reg_setvalue(struct registry_key *key, const char *name,
441                     const struct registry_value *val)
442 {
443         WERROR err;
444         DATA_BLOB value_data;
445         int res;
446
447         if (!(key->key->access_granted & SEC_RIGHTS_SET_VALUE)) {
448                 return WERR_ACCESS_DENIED;
449         }
450
451         if (!W_ERROR_IS_OK(err = fill_value_cache(key))) {
452                 return err;
453         }
454
455         err = registry_push_value(key, val, &value_data);
456         if (!W_ERROR_IS_OK(err)) {
457                 return err;
458         }
459
460         res = regval_ctr_addvalue(key->values, name, val->type,
461                                   (char *)value_data.data, value_data.length);
462         TALLOC_FREE(value_data.data);
463
464         if (res == 0) {
465                 TALLOC_FREE(key->values);
466                 return WERR_NOMEM;
467         }
468
469         if (!store_reg_values(key->key, key->values)) {
470                 TALLOC_FREE(key->values);
471                 return WERR_REG_IO_FAILURE;
472         }
473
474         return WERR_OK;
475 }
476
477 WERROR reg_deletevalue(struct registry_key *key, const char *name)
478 {
479         WERROR err;
480
481         if (!(key->key->access_granted & SEC_RIGHTS_SET_VALUE)) {
482                 return WERR_ACCESS_DENIED;
483         }
484
485         if (!W_ERROR_IS_OK(err = fill_value_cache(key))) {
486                 return err;
487         }
488
489         regval_ctr_delvalue(key->values, name);
490
491         if (!store_reg_values(key->key, key->values)) {
492                 TALLOC_FREE(key->values);
493                 return WERR_REG_IO_FAILURE;
494         }
495
496         return WERR_OK;
497 }
498