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