Add "registry" Group Policy extension.
[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
262         ZERO_STRUCTP(*reg_entry);
263
264         data = TALLOC_ZERO_P(mem_ctx, struct registry_value);
265         if (!data)
266                 return false;
267
268         if (strlen_w((const smb_ucs2_t *)file_entry->key.buffer) <= 0)
269                 return false;
270
271         if (!pull_ucs2_talloc(mem_ctx, &key, file_entry->key.buffer))
272                 return false;
273
274         if (strlen_w((const smb_ucs2_t *)file_entry->value.buffer) > 0) {
275                 if (!pull_ucs2_talloc(mem_ctx, &value,
276                                       file_entry->value.buffer))
277                         return false;
278         }
279
280         if (!reg_parse_value(mem_ctx, &value, &action))
281                 return false;
282
283         data->type = file_entry->type;
284
285         switch (data->type) {
286                 case REG_DWORD:
287                         data->v.dword = atoi((char *)file_entry->data);
288                         break;
289                 case REG_BINARY:
290                         data->v.binary = data_blob_talloc(mem_ctx,
291                                                           file_entry->data,
292                                                           file_entry->size);
293                         break;
294                 case REG_NONE:
295                         break;
296                 case REG_SZ:
297                         data->v.sz.len = pull_ucs2_talloc(mem_ctx,
298                                         &data->v.sz.str,
299                                         (const smb_ucs2_t *)file_entry->data);
300                         break;
301                 case REG_DWORD_BIG_ENDIAN:
302                 case REG_EXPAND_SZ:
303                 case REG_LINK:
304                 case REG_MULTI_SZ:
305                 case REG_QWORD:
306 /*              case REG_DWORD_LITTLE_ENDIAN: */
307 /*              case REG_QWORD_LITTLE_ENDIAN: */
308                         printf("not yet implemented: %d\n", data->type);
309                         return false;
310                 default:
311                         printf("invalid reg type defined: %d\n", data->type);
312                         return false;
313
314         }
315
316         entry = TALLOC_ZERO_P(mem_ctx, struct gp_registry_entry);
317         if (!entry)
318                 return false;
319
320         entry->key = key;
321         entry->value = value;
322         entry->data = data;
323         entry->action = action;
324
325         *reg_entry = entry;
326
327         return true;
328 }
329
330 /****************************************************************
331 * [key;value;type;size;data][key;value;type;size;data]...
332 ****************************************************************/
333
334 static bool reg_parse_entries(TALLOC_CTX *mem_ctx,
335                               const char *desc,
336                               struct gp_registry_entry **entries,
337                               size_t *num_entries,
338                               prs_struct *ps,
339                               int depth)
340 {
341
342         if (!entries || !num_entries)
343                 return false;
344
345         prs_debug(ps, depth, desc, "reg_parse_entries");
346         depth++;
347
348         *entries = NULL;
349         *num_entries = 0;
350
351         while (ps->buffer_size > ps->data_offset) {
352
353                 struct gp_registry_file_entry f_entry;
354                 struct gp_registry_entry *r_entry = NULL;
355
356                 if (!reg_parse_entry(mem_ctx, desc, &f_entry,
357                                      ps, depth))
358                         return false;
359
360                 if (!gp_reg_entry_from_file_entry(mem_ctx,
361                                                   &f_entry,
362                                                   &r_entry))
363                         return false;
364
365                 if (!add_gp_registry_entry_to_array(mem_ctx,
366                                                     r_entry,
367                                                     entries,
368                                                     num_entries))
369                         return false;
370         }
371
372         return true;
373 }
374
375 /****************************************************************
376 ****************************************************************/
377
378 static NTSTATUS reg_parse_registry(TALLOC_CTX *mem_ctx,
379                                    uint32_t flags,
380                                    const char *filename,
381                                    struct gp_registry_entry **entries,
382                                    size_t *num_entries)
383 {
384         uint16_t *buf = NULL;
385         size_t n = 0;
386         NTSTATUS status;
387         prs_struct ps;
388         struct gp_registry_file *reg_file;
389         const char *real_filename = NULL;
390
391         reg_file = TALLOC_ZERO_P(mem_ctx, struct gp_registry_file);
392         NT_STATUS_HAVE_NO_MEMORY(reg_file);
393
394         status = gp_find_file(mem_ctx,
395                               flags,
396                               filename,
397                               GP_REGPOL_FILE,
398                               &real_filename);
399         if (!NT_STATUS_IS_OK(status)) {
400                 TALLOC_FREE(reg_file);
401                 return status;
402         }
403
404         buf = (uint16 *)file_load(real_filename, &n, 0);
405         if (!buf) {
406                 TALLOC_FREE(reg_file);
407                 return NT_STATUS_CANNOT_LOAD_REGISTRY_FILE;
408         }
409
410         if (!prs_init(&ps, n, mem_ctx, UNMARSHALL)) {
411                 status = NT_STATUS_NO_MEMORY;
412                 goto out;
413         }
414
415         if (!prs_copy_data_in(&ps, (char *)buf, n)) {
416                 status = NT_STATUS_NO_MEMORY;
417                 goto out;
418         }
419
420         prs_set_offset(&ps, 0);
421
422         if (!reg_parse_header("header", &reg_file->header, &ps, 0)) {
423                 status = NT_STATUS_REGISTRY_IO_FAILED;
424                 goto out;
425         }
426
427         if (reg_file->header.signature != GP_REGPOL_FILE_SIGNATURE) {
428                 status = NT_STATUS_INVALID_PARAMETER;
429                 goto out;
430         }
431
432         if (reg_file->header.version != GP_REGPOL_FILE_VERSION) {
433                 status = NT_STATUS_INVALID_PARAMETER;
434                 goto out;
435         }
436
437         if (!reg_parse_entries(mem_ctx, "entries", &reg_file->entries,
438                                &reg_file->num_entries, &ps, 0)) {
439                 status = NT_STATUS_REGISTRY_IO_FAILED;
440                 goto out;
441         }
442
443         *entries = reg_file->entries;
444         *num_entries = reg_file->num_entries;
445
446         status = NT_STATUS_OK;
447
448  out:
449         SAFE_FREE(buf);
450         prs_mem_free(&ps);
451
452         return status;
453 }
454
455 /****************************************************************
456 ****************************************************************/
457
458 static WERROR reg_apply_registry(TALLOC_CTX *mem_ctx,
459                                  const struct nt_user_token *token,
460                                  struct registry_key *root_key,
461                                  uint32_t flags,
462                                  struct gp_registry_entry *entries,
463                                  size_t num_entries)
464 {
465         struct gp_registry_context *reg_ctx = NULL;
466         WERROR werr;
467         size_t i;
468
469         if (num_entries == 0) {
470                 return WERR_OK;
471         }
472
473 #if 0
474         if (flags & GPO_LIST_FLAG_MACHINE) {
475                 werr = gp_init_reg_ctx(mem_ctx, KEY_HKLM, REG_KEY_WRITE,
476                                        get_system_token(),
477                                        &reg_ctx);
478         } else {
479                 werr = gp_init_reg_ctx(mem_ctx, KEY_HKCU, REG_KEY_WRITE,
480                                        token,
481                                        &reg_ctx);
482         }
483         W_ERROR_NOT_OK_RETURN(werr);
484 #endif
485         for (i=0; i<num_entries; i++) {
486
487                 /* FIXME: maybe we should check here if we attempt to go beyond
488                  * the 4 allowed reg keys */
489
490                 werr = reg_apply_registry_entry(mem_ctx, root_key,
491                                                 reg_ctx,
492                                                 &(entries)[i],
493                                                 token, flags);
494                 if (!W_ERROR_IS_OK(werr)) {
495                         DEBUG(0,("failed to apply registry: %s\n",
496                                 dos_errstr(werr)));
497                         goto done;
498                 }
499         }
500
501 done:
502         gp_free_reg_ctx(reg_ctx);
503         return werr;
504 }
505
506
507 /****************************************************************
508 ****************************************************************/
509
510 static NTSTATUS registry_process_group_policy(ADS_STRUCT *ads,
511                                               TALLOC_CTX *mem_ctx,
512                                               uint32_t flags,
513                                               struct registry_key *root_key,
514                                               const struct nt_user_token *token,
515                                               struct GROUP_POLICY_OBJECT *gpo,
516                                               const char *extension_guid,
517                                               const char *snapin_guid)
518 {
519         NTSTATUS status;
520         WERROR werr;
521         struct gp_registry_entry *entries = NULL;
522         size_t num_entries = 0;
523         char *unix_path = NULL;
524
525         debug_gpext_header(0, "registry_process_group_policy", flags, gpo,
526                            extension_guid, snapin_guid);
527
528         status = gpo_get_unix_path(mem_ctx, gpo, &unix_path);
529         NT_STATUS_NOT_OK_RETURN(status);
530
531         status = reg_parse_registry(mem_ctx,
532                                     flags,
533                                     unix_path,
534                                     &entries,
535                                     &num_entries);
536         if (!NT_STATUS_IS_OK(status)) {
537                 DEBUG(0,("failed to parse registry: %s\n",
538                         nt_errstr(status)));
539                 return status;
540         }
541
542         dump_reg_entries(flags, "READ", entries, num_entries);
543
544         werr = reg_apply_registry(mem_ctx, token, root_key, flags,
545                                   entries, num_entries);
546         if (!W_ERROR_IS_OK(werr)) {
547                 DEBUG(0,("failed to apply registry: %s\n",
548                         dos_errstr(werr)));
549                 return werror_to_ntstatus(werr);
550         }
551
552         return NT_STATUS_OK;
553 }
554
555 /****************************************************************
556 ****************************************************************/
557
558 static NTSTATUS registry_get_reg_config(TALLOC_CTX *mem_ctx,
559                                         struct gp_extension_reg_info **reg_info)
560 {
561         NTSTATUS status;
562         struct gp_extension_reg_info *info = NULL;
563         struct gp_extension_reg_table table[] = {
564                 { "ProcessGroupPolicy", REG_SZ, "registry_process_group_policy" },
565                 { NULL, REG_NONE, NULL }
566         };
567
568         info = TALLOC_ZERO_P(mem_ctx, struct gp_extension_reg_info);
569         NT_STATUS_HAVE_NO_MEMORY(info);
570
571         status = gp_ext_info_add_entry(mem_ctx, GP_EXT_NAME,
572                                        GP_EXT_GUID_REGISTRY,
573                                        table, info);
574         NT_STATUS_NOT_OK_RETURN(status);
575
576         *reg_info = info;
577
578         return NT_STATUS_OK;
579 }
580
581 /****************************************************************
582 ****************************************************************/
583
584 static NTSTATUS registry_initialize(TALLOC_CTX *mem_ctx)
585 {
586         return NT_STATUS_OK;
587 }
588
589 /****************************************************************
590 ****************************************************************/
591
592 static NTSTATUS registry_shutdown(void)
593 {
594         NTSTATUS status;
595
596         status = unregister_gp_extension(GP_EXT_NAME);
597         if (NT_STATUS_IS_OK(status)) {
598                 return status;
599         }
600
601         TALLOC_FREE(ctx);
602
603         return NT_STATUS_OK;
604 }
605
606 /****************************************************************
607 ****************************************************************/
608
609 static struct gp_extension_methods registry_methods = {
610         .initialize             = registry_initialize,
611         .process_group_policy   = registry_process_group_policy,
612         .get_reg_config         = registry_get_reg_config,
613         .shutdown               = registry_shutdown
614 };
615
616 /****************************************************************
617 ****************************************************************/
618
619 NTSTATUS gpext_registry_init(void)
620 {
621         NTSTATUS status;
622
623         ctx = talloc_init("gpext_registry_init");
624         NT_STATUS_HAVE_NO_MEMORY(ctx);
625
626         status = register_gp_extension(ctx, SMB_GPEXT_INTERFACE_VERSION,
627                                        GP_EXT_NAME, GP_EXT_GUID_REGISTRY,
628                                        &registry_methods);
629         if (!NT_STATUS_IS_OK(status)) {
630                 TALLOC_FREE(ctx);
631         }
632
633         return status;
634 }