r23583: Add a utility function to recursively delete a Registry
[sfrench/samba-autobuild/.git] / source / 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 static int regkey_destructor(REGISTRY_KEY *key)
61 {
62         return regdb_close();
63 }
64
65 static WERROR regkey_open_onelevel(TALLOC_CTX *mem_ctx, 
66                                    struct registry_key *parent,
67                                    const char *name,
68                                    const struct nt_user_token *token,
69                                    uint32 access_desired,
70                                    struct registry_key **pregkey)
71 {
72         WERROR          result = WERR_OK;
73         struct registry_key *regkey;
74         REGISTRY_KEY *key;
75         REGSUBKEY_CTR   *subkeys = NULL;
76
77         DEBUG(7,("regkey_open_onelevel: name = [%s]\n", name));
78
79         SMB_ASSERT(strchr(name, '\\') == NULL);
80
81         if (!(regkey = TALLOC_ZERO_P(mem_ctx, struct registry_key)) ||
82             !(regkey->token = dup_nt_token(regkey, token)) ||
83             !(regkey->key = TALLOC_ZERO_P(regkey, REGISTRY_KEY))) {
84                 result = WERR_NOMEM;
85                 goto done;
86         }
87
88         if ( !(W_ERROR_IS_OK(result = regdb_open())) ) {
89                 goto done;
90         }
91
92         key = regkey->key;
93         talloc_set_destructor(key, regkey_destructor);
94                 
95         /* initialization */
96         
97         key->type = REG_KEY_GENERIC;
98
99         if (name[0] == '\0') {
100                 /*
101                  * Open a copy of the parent key
102                  */
103                 if (!parent) {
104                         result = WERR_BADFILE;
105                         goto done;
106                 }
107                 key->name = talloc_strdup(key, parent->key->name);
108         }
109         else {
110                 /*
111                  * Normal subkey open
112                  */
113                 key->name = talloc_asprintf(key, "%s%s%s",
114                                             parent ? parent->key->name : "",
115                                             parent ? "\\": "",
116                                             name);
117         }
118
119         if (key->name == NULL) {
120                 result = WERR_NOMEM;
121                 goto done;
122         }
123
124         /* Tag this as a Performance Counter Key */
125
126         if( StrnCaseCmp(key->name, KEY_HKPD, strlen(KEY_HKPD)) == 0 )
127                 key->type = REG_KEY_HKPD;
128         
129         /* Look up the table of registry I/O operations */
130
131         if ( !(key->hook = reghook_cache_find( key->name )) ) {
132                 DEBUG(0,("reg_open_onelevel: Failed to assigned a "
133                          "REGISTRY_HOOK to [%s]\n", key->name ));
134                 result = WERR_BADFILE;
135                 goto done;
136         }
137         
138         /* check if the path really exists; failed is indicated by -1 */
139         /* if the subkey count failed, bail out */
140
141         if ( !(subkeys = TALLOC_ZERO_P( key, REGSUBKEY_CTR )) ) {
142                 result = WERR_NOMEM;
143                 goto done;
144         }
145
146         if ( fetch_reg_keys( key, subkeys ) == -1 )  {
147                 result = WERR_BADFILE;
148                 goto done;
149         }
150         
151         TALLOC_FREE( subkeys );
152
153         if ( !regkey_access_check( key, access_desired, &key->access_granted,
154                                    token ) ) {
155                 result = WERR_ACCESS_DENIED;
156                 goto done;
157         }
158
159         *pregkey = regkey;
160         result = WERR_OK;
161         
162 done:
163         if ( !W_ERROR_IS_OK(result) ) {
164                 TALLOC_FREE(regkey);
165         }
166
167         return result;
168 }
169
170 WERROR reg_openhive(TALLOC_CTX *mem_ctx, const char *hive,
171                     uint32 desired_access,
172                     const struct nt_user_token *token,
173                     struct registry_key **pkey)
174 {
175         SMB_ASSERT(hive != NULL);
176         SMB_ASSERT(hive[0] != '\0');
177         SMB_ASSERT(strchr(hive, '\\') == NULL);
178
179         return regkey_open_onelevel(mem_ctx, NULL, hive, token, desired_access,
180                                     pkey);
181 }
182
183 WERROR reg_openkey(TALLOC_CTX *mem_ctx, struct registry_key *parent,
184                    const char *name, uint32 desired_access,
185                    struct registry_key **pkey)
186 {
187         struct registry_key *direct_parent = parent;
188         WERROR err;
189         char *p, *path, *to_free;
190         size_t len;
191
192         if (!(path = SMB_STRDUP(name))) {
193                 return WERR_NOMEM;
194         }
195         to_free = path;
196
197         len = strlen(path);
198
199         if ((len > 0) && (path[len-1] == '\\')) {
200                 path[len-1] = '\0';
201         }
202
203         while ((p = strchr(path, '\\')) != NULL) {
204                 char *name_component;
205                 struct registry_key *tmp;
206
207                 if (!(name_component = SMB_STRNDUP(path, (p - path)))) {
208                         err = WERR_NOMEM;
209                         goto error;
210                 }
211
212                 err = regkey_open_onelevel(mem_ctx, direct_parent,
213                                            name_component, parent->token,
214                                            SEC_RIGHTS_ENUM_SUBKEYS, &tmp);
215                 SAFE_FREE(name_component);
216
217                 if (!W_ERROR_IS_OK(err)) {
218                         goto error;
219                 }
220                 if (direct_parent != parent) {
221                         TALLOC_FREE(direct_parent);
222                 }
223
224                 direct_parent = tmp;
225                 path = p+1;
226         }
227
228         err = regkey_open_onelevel(mem_ctx, direct_parent, path, parent->token,
229                                    desired_access, pkey);
230  error:
231         if (direct_parent != parent) {
232                 TALLOC_FREE(direct_parent);
233         }
234         SAFE_FREE(to_free);
235         return err;
236 }
237
238 WERROR reg_enumkey(TALLOC_CTX *mem_ctx, struct registry_key *key,
239                    uint32 idx, char **name, NTTIME *last_write_time)
240 {
241         WERROR err;
242
243         if (!(key->key->access_granted & SEC_RIGHTS_ENUM_SUBKEYS)) {
244                 return WERR_ACCESS_DENIED;
245         }
246
247         if (!W_ERROR_IS_OK(err = fill_subkey_cache(key))) {
248                 return err;
249         }
250
251         if (idx >= key->subkeys->num_subkeys) {
252                 return WERR_NO_MORE_ITEMS;
253         }
254
255         if (!(*name = talloc_strdup(mem_ctx, key->subkeys->subkeys[idx]))) {
256                 return WERR_NOMEM;
257         }
258
259         if (last_write_time) {
260                 *last_write_time = 0;
261         }
262
263         return WERR_OK;
264 }
265
266 WERROR reg_enumvalue(TALLOC_CTX *mem_ctx, struct registry_key *key,
267                      uint32 idx, char **pname, struct registry_value **pval)
268 {
269         struct registry_value *val;
270         WERROR err;
271
272         if (!(key->key->access_granted & SEC_RIGHTS_QUERY_VALUE)) {
273                 return WERR_ACCESS_DENIED;
274         }
275
276         if (!(W_ERROR_IS_OK(err = fill_value_cache(key)))) {
277                 return err;
278         }
279
280         if (idx >= key->values->num_values) {
281                 return WERR_NO_MORE_ITEMS;
282         }
283
284         err = registry_pull_value(mem_ctx, &val,
285                                   key->values->values[idx]->type,
286                                   key->values->values[idx]->data_p,
287                                   key->values->values[idx]->size,
288                                   key->values->values[idx]->size);
289         if (!W_ERROR_IS_OK(err)) {
290                 return err;
291         }
292
293         if (pname
294             && !(*pname = talloc_strdup(
295                          mem_ctx, key->values->values[idx]->valuename))) {
296                 SAFE_FREE(val);
297                 return WERR_NOMEM;
298         }
299                 
300         *pval = val;
301         return WERR_OK;
302 }
303
304 WERROR reg_queryvalue(TALLOC_CTX *mem_ctx, struct registry_key *key,
305                       const char *name, struct registry_value **pval)
306 {
307         WERROR err;
308         uint32 i;
309
310         if (!(key->key->access_granted & SEC_RIGHTS_QUERY_VALUE)) {
311                 return WERR_ACCESS_DENIED;
312         }
313
314         if (!(W_ERROR_IS_OK(err = fill_value_cache(key)))) {
315                 return err;
316         }
317
318         for (i=0; i<key->values->num_values; i++) {
319                 if (strequal(key->values->values[i]->valuename, name)) {
320                         return reg_enumvalue(mem_ctx, key, i, NULL, pval);
321                 }
322         }
323
324         return WERR_BADFILE;
325 }
326
327 WERROR reg_queryinfokey(struct registry_key *key, uint32_t *num_subkeys,
328                         uint32_t *max_subkeylen, uint32_t *max_subkeysize, 
329                         uint32_t *num_values, uint32_t *max_valnamelen, 
330                         uint32_t *max_valbufsize, uint32_t *secdescsize,
331                         NTTIME *last_changed_time)
332 {
333         uint32 i, max_size;
334         size_t max_len;
335         TALLOC_CTX *mem_ctx;
336         WERROR err;
337         struct security_descriptor *secdesc;
338
339         if (!(key->key->access_granted & SEC_RIGHTS_QUERY_VALUE)) {
340                 return WERR_ACCESS_DENIED;
341         }
342
343         if (!W_ERROR_IS_OK(fill_subkey_cache(key)) ||
344             !W_ERROR_IS_OK(fill_value_cache(key))) {
345                 return WERR_BADFILE;
346         }
347
348         max_len = 0;
349         for (i=0; i<key->subkeys->num_subkeys; i++) {
350                 max_len = MAX(max_len, strlen(key->subkeys->subkeys[i]));
351         }
352
353         *num_subkeys = key->subkeys->num_subkeys;
354         *max_subkeylen = max_len;
355         *max_subkeysize = 0;    /* Class length? */
356
357         max_len = 0;
358         max_size = 0;
359         for (i=0; i<key->values->num_values; i++) {
360                 max_len = MAX(max_len,
361                               strlen(key->values->values[i]->valuename));
362                 max_size = MAX(max_size, key->values->values[i]->size);
363         }
364
365         *num_values = key->values->num_values;
366         *max_valnamelen = max_len;
367         *max_valbufsize = max_size;
368
369         if (!(mem_ctx = talloc_new(key))) {
370                 return WERR_NOMEM;
371         }
372
373         err = regkey_get_secdesc(mem_ctx, key->key, &secdesc);
374         if (!W_ERROR_IS_OK(err)) {
375                 TALLOC_FREE(mem_ctx);
376                 return err;
377         }
378
379         *secdescsize = sec_desc_size(secdesc);
380         TALLOC_FREE(mem_ctx);
381
382         *last_changed_time = 0;
383
384         return WERR_OK;
385 }
386
387 WERROR reg_createkey(TALLOC_CTX *ctx, struct registry_key *parent,
388                      const char *subkeypath, uint32 desired_access,
389                      struct registry_key **pkey,
390                      enum winreg_CreateAction *paction)
391 {
392         struct registry_key *key = parent;
393         struct registry_key *create_parent;
394         TALLOC_CTX *mem_ctx;
395         char *path, *end;
396         WERROR err;
397         REGSUBKEY_CTR *subkeys;
398
399         if (!(mem_ctx = talloc_new(ctx))) return WERR_NOMEM;
400
401         if (!(path = talloc_strdup(mem_ctx, subkeypath))) {
402                 err = WERR_NOMEM;
403                 goto done;
404         }
405
406         while ((end = strchr(path, '\\')) != NULL) {
407                 struct registry_key *tmp;
408                 enum winreg_CreateAction action;
409
410                 *end = '\0';
411
412                 err = reg_createkey(mem_ctx, key, path,
413                                     SEC_RIGHTS_ENUM_SUBKEYS, &tmp, &action);
414                 if (!W_ERROR_IS_OK(err)) {
415                         goto done;
416                 }
417
418                 if (key != parent) {
419                         TALLOC_FREE(key);
420                 }
421
422                 key = tmp;
423                 path = end+1;
424         }
425
426         /*
427          * At this point, "path" contains the one-element subkey of "key". We
428          * can try to open it.
429          */
430
431         err = reg_openkey(ctx, key, path, desired_access, pkey);
432         if (W_ERROR_IS_OK(err)) {
433                 if (paction != NULL) {
434                         *paction = REG_OPENED_EXISTING_KEY;
435                 }
436                 goto done;
437         }
438
439         if (!W_ERROR_EQUAL(err, WERR_BADFILE)) {
440                 /*
441                  * Something but "notfound" has happened, so bail out
442                  */
443                 goto done;
444         }
445
446         /*
447          * We have to make a copy of the current key, as we opened it only
448          * with ENUM_SUBKEY access.
449          */
450
451         err = reg_openkey(mem_ctx, key, "", SEC_RIGHTS_CREATE_SUBKEY,
452                           &create_parent);
453         if (!W_ERROR_IS_OK(err)) {
454                 goto done;
455         }
456
457         /*
458          * Actually create the subkey
459          */
460
461         if (!(subkeys = TALLOC_ZERO_P(mem_ctx, REGSUBKEY_CTR))) {
462                 err = WERR_NOMEM;
463                 goto done;
464         }
465
466         err = fill_subkey_cache(create_parent);
467         if (!W_ERROR_IS_OK(err)) goto done;
468
469         err = regsubkey_ctr_addkey(create_parent->subkeys, path);
470         if (!W_ERROR_IS_OK(err)) goto done;
471
472         if (!store_reg_keys(create_parent->key, create_parent->subkeys)) {
473                 TALLOC_FREE(create_parent->subkeys);
474                 err = WERR_REG_IO_FAILURE;
475                 goto done;
476         }
477
478         /*
479          * Now open the newly created key
480          */
481
482         err = reg_openkey(ctx, create_parent, path, desired_access, pkey);
483         if (W_ERROR_IS_OK(err) && (paction != NULL)) {
484                 *paction = REG_CREATED_NEW_KEY;
485         }
486
487  done:
488         TALLOC_FREE(mem_ctx);
489         return err;
490 }
491                      
492
493 WERROR reg_deletekey(struct registry_key *parent, const char *path)
494 {
495         WERROR err;
496         TALLOC_CTX *mem_ctx;
497         char *name, *end;
498         int num_subkeys;
499         struct registry_key *tmp_key;
500
501         if (!(mem_ctx = talloc_init("reg_createkey"))) return WERR_NOMEM;
502
503         if (!(name = talloc_strdup(mem_ctx, path))) {
504                 err = WERR_NOMEM;
505                 goto error;
506         }
507
508         /* check if the key has subkeys */
509         err = reg_openkey(mem_ctx, parent, name, REG_KEY_READ, &tmp_key);
510         if (!W_ERROR_IS_OK(err)) {
511                 goto error;
512         }
513         if (!W_ERROR_IS_OK(err = fill_subkey_cache(tmp_key))) {
514                 goto error;
515         }
516         if (tmp_key->subkeys->num_subkeys > 0) {
517                 err = WERR_ACCESS_DENIED;
518                 goto error;
519         }
520
521         /* no subkeys - proceed with delete */
522         if ((end = strrchr(name, '\\')) != NULL) {
523                 *end = '\0';
524
525                 err = reg_openkey(mem_ctx, parent, name,
526                                   SEC_RIGHTS_CREATE_SUBKEY, &tmp_key);
527                 if (!W_ERROR_IS_OK(err)) {
528                         goto error;
529                 }
530
531                 parent = tmp_key;
532                 name = end+1;
533         }
534
535         if (name[0] == '\0') {
536                 err = WERR_INVALID_PARAM;
537                 goto error;
538         }
539
540         if (!W_ERROR_IS_OK(err = fill_subkey_cache(parent))) {
541                 goto error;
542         }
543
544         num_subkeys = parent->subkeys->num_subkeys;
545
546         if (regsubkey_ctr_delkey(parent->subkeys, name) == num_subkeys) {
547                 err = WERR_BADFILE;
548                 goto error;
549         }
550
551         if (!store_reg_keys(parent->key, parent->subkeys)) {
552                 TALLOC_FREE(parent->subkeys);
553                 err = WERR_REG_IO_FAILURE;
554                 goto error;
555         }
556
557         err = WERR_OK;
558  error:
559         TALLOC_FREE(mem_ctx);
560         return err;
561 }
562
563 WERROR reg_setvalue(struct registry_key *key, const char *name,
564                     const struct registry_value *val)
565 {
566         WERROR err;
567         DATA_BLOB value_data;
568         int res;
569
570         if (!(key->key->access_granted & SEC_RIGHTS_SET_VALUE)) {
571                 return WERR_ACCESS_DENIED;
572         }
573
574         if (!W_ERROR_IS_OK(err = fill_value_cache(key))) {
575                 return err;
576         }
577
578         err = registry_push_value(key, val, &value_data);
579         if (!W_ERROR_IS_OK(err)) {
580                 return err;
581         }
582
583         res = regval_ctr_addvalue(key->values, name, val->type,
584                                   (char *)value_data.data, value_data.length);
585         TALLOC_FREE(value_data.data);
586
587         if (res == 0) {
588                 TALLOC_FREE(key->values);
589                 return WERR_NOMEM;
590         }
591
592         if (!store_reg_values(key->key, key->values)) {
593                 TALLOC_FREE(key->values);
594                 return WERR_REG_IO_FAILURE;
595         }
596
597         return WERR_OK;
598 }
599
600 WERROR reg_deletevalue(struct registry_key *key, const char *name)
601 {
602         WERROR err;
603
604         if (!(key->key->access_granted & SEC_RIGHTS_SET_VALUE)) {
605                 return WERR_ACCESS_DENIED;
606         }
607
608         if (!W_ERROR_IS_OK(err = fill_value_cache(key))) {
609                 return err;
610         }
611
612         regval_ctr_delvalue(key->values, name);
613
614         if (!store_reg_values(key->key, key->values)) {
615                 TALLOC_FREE(key->values);
616                 return WERR_REG_IO_FAILURE;
617         }
618
619         return WERR_OK;
620 }
621
622
623 /*
624  * Utility function to open a complete registry path including the hive
625  * prefix. This should become the replacement function for
626  * regkey_open_internal.
627  */
628
629 WERROR reg_open_path(TALLOC_CTX *mem_ctx, const char *orig_path,
630                      uint32 desired_access, const struct nt_user_token *token,
631                      struct registry_key **pkey)
632 {
633         struct registry_key *hive, *key;
634         char *path, *p;
635         WERROR err;
636
637         if (!(path = SMB_STRDUP(orig_path))) {
638                 return WERR_NOMEM;
639         }
640
641         p = strchr(path, '\\');
642
643         if ((p == NULL) || (p[1] == '\0')) {
644                 /*
645                  * No key behind the hive, just return the hive
646                  */
647
648                 err = reg_openhive(mem_ctx, path, desired_access, token,
649                                    &hive);
650                 if (!W_ERROR_IS_OK(err)) {
651                         SAFE_FREE(path);
652                         return err;
653                 }
654                 SAFE_FREE(path);
655                 *pkey = hive;
656                 return WERR_OK;
657         }
658
659         *p = '\0';
660
661         err = reg_openhive(mem_ctx, path, SEC_RIGHTS_ENUM_SUBKEYS, token,
662                            &hive);
663         if (!W_ERROR_IS_OK(err)) {
664                 SAFE_FREE(path);
665                 return err;
666         }
667
668         err = reg_openkey(mem_ctx, hive, p+1, desired_access, &key);
669
670         TALLOC_FREE(hive);
671         SAFE_FREE(path);
672
673         if (!W_ERROR_IS_OK(err)) {
674                 return err;
675         }
676
677         *pkey = key;
678         return WERR_OK;
679 }
680
681
682 /*
683  * Utility function to delete a registry key with all its subkeys. 
684  * Note that reg_deletekey returns ACCESS_DENIED when called on a 
685  * key that has subkeys.
686  */
687 WERROR reg_deletekey_recursive(TALLOC_CTX *ctx,
688                                struct registry_key *parent, 
689                                const char *path)
690 {
691         TALLOC_CTX *mem_ctx = NULL;
692         WERROR werr = WERR_OK;
693         struct registry_key *key;
694         uint32 idx = 0;
695         char *subkey_name = NULL;
696
697         mem_ctx = talloc_new(ctx);
698         if (mem_ctx == NULL) {
699                 werr = WERR_NOMEM;
700                 goto done;
701         }
702
703         /* recurse through subkeys first */
704         werr = reg_openkey(mem_ctx, parent, path, REG_KEY_WRITE, &key);
705         if (!W_ERROR_IS_OK(werr)) {
706                 goto done;
707         }
708
709         /* NOTE: we *must not* increment idx in this loop since
710          * the list of subkeys shrinks with each loop body. 
711          * so this way, we repeatedly delete the *first* entry
712          * of a shrinking list. */
713         for (idx = 0;
714              W_ERROR_IS_OK(werr = reg_enumkey(mem_ctx, key, idx,
715                                               &subkey_name, NULL));
716             ) 
717         {
718                 werr = reg_deletekey_recursive(mem_ctx, key, subkey_name);
719                 if (!W_ERROR_IS_OK(werr)) {
720                         goto done;
721                 }
722         }
723         if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) {
724                 DEBUG(1, ("reg_deletekey_recursive: Error enumerating "
725                           "subkeys: %s\n", dos_errstr(werr)));
726                 goto done;
727         }
728
729         /* now delete the actual key */
730         werr = reg_deletekey(parent, path);
731         
732 done:
733         TALLOC_FREE(mem_ctx);
734         return werr;
735 }