Merge branch 'v3-3-test' of ssh://git.samba.org/data/git/samba into docbook
[sfrench/samba-autobuild/.git] / source3 / libgpo / gpext / registry.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  Group Policy Support
4  *  Copyright (C) Guenther Deschner 2007-2008
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 3 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, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21
22 #define GP_EXT_NAME "registry"
23
24 /* more info can be found at:
25  * http://msdn2.microsoft.com/en-us/library/aa374407.aspx */
26
27 #define GP_REGPOL_FILE  "Registry.pol"
28
29 #define GP_REGPOL_FILE_SIGNATURE 0x67655250 /* 'PReg' */
30 #define GP_REGPOL_FILE_VERSION 1
31
32 static TALLOC_CTX *ctx = NULL;
33
34 struct gp_registry_file_header {
35         uint32_t signature;
36         uint32_t version;
37 };
38
39 struct gp_registry_file_entry {
40         UNISTR key;
41         UNISTR value;
42         enum winreg_Type type;
43         size_t size;
44         uint8_t *data;
45 };
46
47 struct gp_registry_file {
48         struct gp_registry_file_header header;
49         size_t num_entries;
50         struct gp_registry_entry *entries;
51 };
52
53 /****************************************************************
54 ****************************************************************/
55
56 static bool reg_parse_header(const char *desc,
57                              struct gp_registry_file_header *header,
58                              prs_struct *ps,
59                              int depth)
60 {
61         if (!header)
62                 return false;
63
64         prs_debug(ps, depth, desc, "reg_parse_header");
65         depth++;
66
67         if (!prs_uint32("signature", ps, depth, &header->signature))
68                 return false;
69
70         if (!prs_uint32("version", ps, depth, &header->version))
71                 return false;
72
73         return true;
74 }
75
76 /****************************************************************
77 ****************************************************************/
78
79 static bool reg_parse_and_verify_ucs2_char(const char *desc,
80                                            char character,
81                                            prs_struct *ps,
82                                            int depth)
83 {
84         uint16_t tmp;
85
86         if (!prs_uint16(desc, ps, depth, &tmp))
87                 return false;
88
89         if (tmp != UCS2_CHAR(character))
90                 return false;
91
92         return true;
93 }
94
95 /****************************************************************
96 ****************************************************************/
97
98 static bool reg_parse_init(prs_struct *ps, int depth)
99 {
100         return reg_parse_and_verify_ucs2_char("initiator '['", '[',
101                                               ps, depth);
102 }
103
104 /****************************************************************
105 ****************************************************************/
106
107 static bool reg_parse_sep(prs_struct *ps, int depth)
108 {
109         return reg_parse_and_verify_ucs2_char("separator ';'", ';',
110                                               ps, depth);
111 }
112
113 /****************************************************************
114 ****************************************************************/
115
116 static bool reg_parse_term(prs_struct *ps, int depth)
117 {
118         return reg_parse_and_verify_ucs2_char("terminator ']'", ']',
119                                               ps, depth);
120 }
121
122
123 /****************************************************************
124 * [key;value;type;size;data]
125 ****************************************************************/
126
127 static bool reg_parse_entry(TALLOC_CTX *mem_ctx,
128                             const char *desc,
129                             struct gp_registry_file_entry *entry,
130                             prs_struct *ps,
131                             int depth)
132 {
133         uint32_t size = 0;
134
135         if (!entry)
136                 return false;
137
138         prs_debug(ps, depth, desc, "reg_parse_entry");
139         depth++;
140
141         ZERO_STRUCTP(entry);
142
143         if (!reg_parse_init(ps, depth))
144                 return false;
145
146         if (!prs_unistr("key", ps, depth, &entry->key))
147                 return false;
148
149         if (!reg_parse_sep(ps, depth))
150                 return false;
151
152         if (!prs_unistr("value", ps, depth, &entry->value))
153                 return false;
154
155         if (!reg_parse_sep(ps, depth))
156                 return false;
157
158         if (!prs_uint32("type", ps, depth, &entry->type))
159                 return false;
160
161         if (!reg_parse_sep(ps, depth))
162                 return false;
163
164         if (!prs_uint32("size", ps, depth, &size))
165                 return false;
166
167         entry->size = size;
168
169         if (!reg_parse_sep(ps, depth))
170                 return false;
171
172         if (entry->size) {
173                 entry->data = TALLOC_ZERO_ARRAY(mem_ctx, uint8, entry->size);
174                 if (!entry->data)
175                         return false;
176         }
177
178         if (!prs_uint8s(false, "data", ps, depth, entry->data, entry->size))
179                 return false;
180
181         if (!reg_parse_term(ps, depth))
182                 return false;
183
184         return true;
185 }
186
187 /****************************************************************
188 ****************************************************************/
189
190 static bool reg_parse_value(TALLOC_CTX *mem_ctx,
191                             char **value,
192                             enum gp_reg_action *action)
193 {
194         if (!*value) {
195                 *action = GP_REG_ACTION_ADD_KEY;
196                 return true;
197         }
198
199         if (strncmp(*value, "**", 2) != 0) {
200                 *action = GP_REG_ACTION_ADD_VALUE;
201                 return true;
202         }
203
204         if (strnequal(*value, "**DelVals.", 10)) {
205                 *action = GP_REG_ACTION_DEL_ALL_VALUES;
206                 return true;
207         }
208
209         if (strnequal(*value, "**Del.", 6)) {
210                 *value = talloc_strdup(mem_ctx, *value + 6);
211                 *action = GP_REG_ACTION_DEL_VALUE;
212                 return true;
213         }
214
215         if (strnequal(*value, "**SecureKey", 11)) {
216                 if (strnequal(*value, "**SecureKey=1", 13)) {
217                         *action = GP_REG_ACTION_SEC_KEY_SET;
218                         return true;
219                 }
220
221  /*************** not tested from here on ***************/
222                 if (strnequal(*value, "**SecureKey=0", 13)) {
223                         smb_panic("not supported: **SecureKey=0");
224                         *action = GP_REG_ACTION_SEC_KEY_RESET;
225                         return true;
226                 }
227                 DEBUG(0,("unknown: SecureKey: %s\n", *value));
228                 smb_panic("not supported SecureKey method");
229                 return false;
230         }
231
232         if (strnequal(*value, "**DeleteValues", strlen("**DeleteValues"))) {
233                 smb_panic("not supported: **DeleteValues");
234                 *action = GP_REG_ACTION_DEL_VALUES;
235                 return false;
236         }
237
238         if (strnequal(*value, "**DeleteKeys", strlen("**DeleteKeys"))) {
239                 smb_panic("not supported: **DeleteKeys");
240                 *action = GP_REG_ACTION_DEL_KEYS;
241                 return false;
242         }
243
244         DEBUG(0,("unknown value: %s\n", *value));
245         smb_panic(*value);
246         return false;
247 }
248
249 /****************************************************************
250 ****************************************************************/
251
252 static bool gp_reg_entry_from_file_entry(TALLOC_CTX *mem_ctx,
253                                          struct gp_registry_file_entry *file_entry,
254                                          struct gp_registry_entry **reg_entry)
255 {
256         struct registry_value *data = NULL;
257         struct gp_registry_entry *entry = NULL;
258         char *key = NULL;
259         char *value = NULL;
260         enum gp_reg_action action = GP_REG_ACTION_NONE;
261         size_t converted_size;
262
263         ZERO_STRUCTP(*reg_entry);
264
265         data = TALLOC_ZERO_P(mem_ctx, struct registry_value);
266         if (!data)
267                 return false;
268
269         if (strlen_w((const smb_ucs2_t *)file_entry->key.buffer) <= 0)
270                 return false;
271
272         if (!pull_ucs2_talloc(mem_ctx, &key, file_entry->key.buffer,
273                               &converted_size))
274         {
275                 return false;
276         }
277
278         if (strlen_w((const smb_ucs2_t *)file_entry->value.buffer) > 0 &&
279             !pull_ucs2_talloc(mem_ctx, &value, file_entry->value.buffer,
280                               &converted_size))
281         {
282                         return false;
283         }
284
285         if (!reg_parse_value(mem_ctx, &value, &action))
286                 return false;
287
288         data->type = file_entry->type;
289
290         switch (data->type) {
291                 case REG_DWORD:
292                         data->v.dword = atoi((char *)file_entry->data);
293                         break;
294                 case REG_BINARY:
295                         data->v.binary = data_blob_talloc(mem_ctx,
296                                                           file_entry->data,
297                                                           file_entry->size);
298                         break;
299                 case REG_NONE:
300                         break;
301                 case REG_SZ:
302                         if (!pull_ucs2_talloc(mem_ctx, &data->v.sz.str,
303                                               (const smb_ucs2_t *)
304                                               file_entry->data,
305                                               &data->v.sz.len)) {
306                                 data->v.sz.len = -1;
307                         }
308
309                         break;
310                 case REG_DWORD_BIG_ENDIAN:
311                 case REG_EXPAND_SZ:
312                 case REG_LINK:
313                 case REG_MULTI_SZ:
314                 case REG_QWORD:
315 /*              case REG_DWORD_LITTLE_ENDIAN: */
316 /*              case REG_QWORD_LITTLE_ENDIAN: */
317                         printf("not yet implemented: %d\n", data->type);
318                         return false;
319                 default:
320                         printf("invalid reg type defined: %d\n", data->type);
321                         return false;
322
323         }
324
325         entry = TALLOC_ZERO_P(mem_ctx, struct gp_registry_entry);
326         if (!entry)
327                 return false;
328
329         entry->key = key;
330         entry->value = value;
331         entry->data = data;
332         entry->action = action;
333
334         *reg_entry = entry;
335
336         return true;
337 }
338
339 /****************************************************************
340 * [key;value;type;size;data][key;value;type;size;data]...
341 ****************************************************************/
342
343 static bool reg_parse_entries(TALLOC_CTX *mem_ctx,
344                               const char *desc,
345                               struct gp_registry_entry **entries,
346                               size_t *num_entries,
347                               prs_struct *ps,
348                               int depth)
349 {
350
351         if (!entries || !num_entries)
352                 return false;
353
354         prs_debug(ps, depth, desc, "reg_parse_entries");
355         depth++;
356
357         *entries = NULL;
358         *num_entries = 0;
359
360         while (ps->buffer_size > ps->data_offset) {
361
362                 struct gp_registry_file_entry f_entry;
363                 struct gp_registry_entry *r_entry = NULL;
364
365                 if (!reg_parse_entry(mem_ctx, desc, &f_entry,
366                                      ps, depth))
367                         return false;
368
369                 if (!gp_reg_entry_from_file_entry(mem_ctx,
370                                                   &f_entry,
371                                                   &r_entry))
372                         return false;
373
374                 if (!add_gp_registry_entry_to_array(mem_ctx,
375                                                     r_entry,
376                                                     entries,
377                                                     num_entries))
378                         return false;
379         }
380
381         return true;
382 }
383
384 /****************************************************************
385 ****************************************************************/
386
387 static NTSTATUS reg_parse_registry(TALLOC_CTX *mem_ctx,
388                                    uint32_t flags,
389                                    const char *filename,
390                                    struct gp_registry_entry **entries,
391                                    size_t *num_entries)
392 {
393         uint16_t *buf = NULL;
394         size_t n = 0;
395         NTSTATUS status;
396         prs_struct ps;
397         struct gp_registry_file *reg_file;
398         const char *real_filename = NULL;
399
400         reg_file = TALLOC_ZERO_P(mem_ctx, struct gp_registry_file);
401         NT_STATUS_HAVE_NO_MEMORY(reg_file);
402
403         status = gp_find_file(mem_ctx,
404                               flags,
405                               filename,
406                               GP_REGPOL_FILE,
407                               &real_filename);
408         if (!NT_STATUS_IS_OK(status)) {
409                 TALLOC_FREE(reg_file);
410                 return status;
411         }
412
413         buf = (uint16 *)file_load(real_filename, &n, 0);
414         if (!buf) {
415                 TALLOC_FREE(reg_file);
416                 return NT_STATUS_CANNOT_LOAD_REGISTRY_FILE;
417         }
418
419         if (!prs_init(&ps, n, mem_ctx, UNMARSHALL)) {
420                 status = NT_STATUS_NO_MEMORY;
421                 goto out;
422         }
423
424         if (!prs_copy_data_in(&ps, (char *)buf, n)) {
425                 status = NT_STATUS_NO_MEMORY;
426                 goto out;
427         }
428
429         prs_set_offset(&ps, 0);
430
431         if (!reg_parse_header("header", &reg_file->header, &ps, 0)) {
432                 status = NT_STATUS_REGISTRY_IO_FAILED;
433                 goto out;
434         }
435
436         if (reg_file->header.signature != GP_REGPOL_FILE_SIGNATURE) {
437                 status = NT_STATUS_INVALID_PARAMETER;
438                 goto out;
439         }
440
441         if (reg_file->header.version != GP_REGPOL_FILE_VERSION) {
442                 status = NT_STATUS_INVALID_PARAMETER;
443                 goto out;
444         }
445
446         if (!reg_parse_entries(mem_ctx, "entries", &reg_file->entries,
447                                &reg_file->num_entries, &ps, 0)) {
448                 status = NT_STATUS_REGISTRY_IO_FAILED;
449                 goto out;
450         }
451
452         *entries = reg_file->entries;
453         *num_entries = reg_file->num_entries;
454
455         status = NT_STATUS_OK;
456
457  out:
458         SAFE_FREE(buf);
459         prs_mem_free(&ps);
460
461         return status;
462 }
463
464 /****************************************************************
465 ****************************************************************/
466
467 static WERROR reg_apply_registry(TALLOC_CTX *mem_ctx,
468                                  const struct nt_user_token *token,
469                                  struct registry_key *root_key,
470                                  uint32_t flags,
471                                  struct gp_registry_entry *entries,
472                                  size_t num_entries)
473 {
474         struct gp_registry_context *reg_ctx = NULL;
475         WERROR werr;
476         size_t i;
477
478         if (num_entries == 0) {
479                 return WERR_OK;
480         }
481
482 #if 0
483         if (flags & GPO_LIST_FLAG_MACHINE) {
484                 werr = gp_init_reg_ctx(mem_ctx, KEY_HKLM, REG_KEY_WRITE,
485                                        get_system_token(),
486                                        &reg_ctx);
487         } else {
488                 werr = gp_init_reg_ctx(mem_ctx, KEY_HKCU, REG_KEY_WRITE,
489                                        token,
490                                        &reg_ctx);
491         }
492         W_ERROR_NOT_OK_RETURN(werr);
493 #endif
494         for (i=0; i<num_entries; i++) {
495
496                 /* FIXME: maybe we should check here if we attempt to go beyond
497                  * the 4 allowed reg keys */
498
499                 werr = reg_apply_registry_entry(mem_ctx, root_key,
500                                                 reg_ctx,
501                                                 &(entries)[i],
502                                                 token, flags);
503                 if (!W_ERROR_IS_OK(werr)) {
504                         DEBUG(0,("failed to apply registry: %s\n",
505                                 dos_errstr(werr)));
506                         goto done;
507                 }
508         }
509
510 done:
511         gp_free_reg_ctx(reg_ctx);
512         return werr;
513 }
514
515
516 /****************************************************************
517 ****************************************************************/
518
519 static NTSTATUS registry_process_group_policy(ADS_STRUCT *ads,
520                                               TALLOC_CTX *mem_ctx,
521                                               uint32_t flags,
522                                               struct registry_key *root_key,
523                                               const struct nt_user_token *token,
524                                               struct GROUP_POLICY_OBJECT *gpo,
525                                               const char *extension_guid,
526                                               const char *snapin_guid)
527 {
528         NTSTATUS status;
529         WERROR werr;
530         struct gp_registry_entry *entries = NULL;
531         size_t num_entries = 0;
532         char *unix_path = NULL;
533
534         debug_gpext_header(0, "registry_process_group_policy", flags, gpo,
535                            extension_guid, snapin_guid);
536
537         status = gpo_get_unix_path(mem_ctx, gpo, &unix_path);
538         NT_STATUS_NOT_OK_RETURN(status);
539
540         status = reg_parse_registry(mem_ctx,
541                                     flags,
542                                     unix_path,
543                                     &entries,
544                                     &num_entries);
545         if (!NT_STATUS_IS_OK(status)) {
546                 DEBUG(0,("failed to parse registry: %s\n",
547                         nt_errstr(status)));
548                 return status;
549         }
550
551         dump_reg_entries(flags, "READ", entries, num_entries);
552
553         werr = reg_apply_registry(mem_ctx, token, root_key, flags,
554                                   entries, num_entries);
555         if (!W_ERROR_IS_OK(werr)) {
556                 DEBUG(0,("failed to apply registry: %s\n",
557                         dos_errstr(werr)));
558                 return werror_to_ntstatus(werr);
559         }
560
561         return NT_STATUS_OK;
562 }
563
564 /****************************************************************
565 ****************************************************************/
566
567 static NTSTATUS registry_get_reg_config(TALLOC_CTX *mem_ctx,
568                                         struct gp_extension_reg_info **reg_info)
569 {
570         NTSTATUS status;
571         struct gp_extension_reg_info *info = NULL;
572         struct gp_extension_reg_table table[] = {
573                 { "ProcessGroupPolicy", REG_SZ, "registry_process_group_policy" },
574                 { NULL, REG_NONE, NULL }
575         };
576
577         info = TALLOC_ZERO_P(mem_ctx, struct gp_extension_reg_info);
578         NT_STATUS_HAVE_NO_MEMORY(info);
579
580         status = gp_ext_info_add_entry(mem_ctx, GP_EXT_NAME,
581                                        GP_EXT_GUID_REGISTRY,
582                                        table, info);
583         NT_STATUS_NOT_OK_RETURN(status);
584
585         *reg_info = info;
586
587         return NT_STATUS_OK;
588 }
589
590 /****************************************************************
591 ****************************************************************/
592
593 static NTSTATUS registry_initialize(TALLOC_CTX *mem_ctx)
594 {
595         return NT_STATUS_OK;
596 }
597
598 /****************************************************************
599 ****************************************************************/
600
601 static NTSTATUS registry_shutdown(void)
602 {
603         NTSTATUS status;
604
605         status = unregister_gp_extension(GP_EXT_NAME);
606         if (NT_STATUS_IS_OK(status)) {
607                 return status;
608         }
609
610         TALLOC_FREE(ctx);
611
612         return NT_STATUS_OK;
613 }
614
615 /****************************************************************
616 ****************************************************************/
617
618 static struct gp_extension_methods registry_methods = {
619         .initialize             = registry_initialize,
620         .process_group_policy   = registry_process_group_policy,
621         .get_reg_config         = registry_get_reg_config,
622         .shutdown               = registry_shutdown
623 };
624
625 /****************************************************************
626 ****************************************************************/
627
628 NTSTATUS gpext_registry_init(void)
629 {
630         NTSTATUS status;
631
632         ctx = talloc_init("gpext_registry_init");
633         NT_STATUS_HAVE_NO_MEMORY(ctx);
634
635         status = register_gp_extension(ctx, SMB_GPEXT_INTERFACE_VERSION,
636                                        GP_EXT_NAME, GP_EXT_GUID_REGISTRY,
637                                        &registry_methods);
638         if (!NT_STATUS_IS_OK(status)) {
639                 TALLOC_FREE(ctx);
640         }
641
642         return status;
643 }