s3-gpo: Build scripts, security and registry CSE with --enable-developer
[samba.git] / source3 / libgpo / gpext / scripts.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  Group Policy Support
4  *  Copyright (C) Guenther Deschner 2007
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 #include "registry.h"
25 #include "registry/reg_api.h"
26 #include "../libcli/registry/util_reg.h"
27 #include "libgpo/gpext/gpext.h"
28
29 #define GP_EXT_NAME "scripts"
30
31 #define KEY_GP_SCRIPTS "Software\\Policies\\Microsoft\\Windows\\System\\Scripts"
32
33 #define GP_SCRIPTS_INI "Scripts/scripts.ini"
34
35 #define GP_SCRIPTS_INI_STARTUP "Startup"
36 #define GP_SCRIPTS_INI_SHUTDOWN "Shutdown"
37 #define GP_SCRIPTS_INI_LOGON "Logon"
38 #define GP_SCRIPTS_INI_LOGOFF "Logoff"
39
40 #define GP_SCRIPTS_SECTION_CMDLINE "cmdline"
41 #define GP_SCRIPTS_SECTION_PARAMETERS "parameters"
42
43 #define GP_SCRIPTS_REG_VAL_SCRIPT "Script"
44 #define GP_SCRIPTS_REG_VAL_PARAMETERS "Parameters"
45 #define GP_SCRIPTS_REG_VAL_EXECTIME "ExecTime"
46
47 NTSTATUS gpext_scripts_init(TALLOC_CTX *mem_ctx);
48
49 static TALLOC_CTX *ctx = NULL;
50
51 /****************************************************************
52 ****************************************************************/
53
54 static NTSTATUS scripts_get_reg_config(TALLOC_CTX *mem_ctx,
55                                        struct gp_extension_reg_info **reg_info)
56 {
57         NTSTATUS status;
58         struct gp_extension_reg_info *info = NULL;
59
60         struct gp_extension_reg_table table[] = {
61                 { "ProcessGroupPolicy", REG_SZ, "scripts_process_group_policy" },
62                 { "NoGPOListChanges", REG_DWORD, "1" },
63                 { "NoSlowLink", REG_DWORD, "1" },
64                 { "NotifyLinkTransition", REG_DWORD, "1" },
65                 { NULL, REG_NONE, NULL },
66         };
67
68         info = talloc_zero(mem_ctx, struct gp_extension_reg_info);
69         NT_STATUS_HAVE_NO_MEMORY(info);
70
71         status = gpext_info_add_entry(mem_ctx, GP_EXT_NAME,
72                                       GP_EXT_GUID_SCRIPTS,
73                                       table, info);
74         NT_STATUS_NOT_OK_RETURN(status);
75
76         *reg_info = info;
77
78         return NT_STATUS_OK;
79 }
80
81 /****************************************************************
82 ****************************************************************/
83
84 static NTSTATUS generate_gp_registry_entry(TALLOC_CTX *mem_ctx,
85                                            const char *key,
86                                            const char *value,
87                                            uint32_t data_type,
88                                            DATA_BLOB *blob,
89                                            enum gp_reg_action action,
90                                            struct gp_registry_entry **entry_out)
91 {
92         struct gp_registry_entry *entry = NULL;
93         struct registry_value *data = NULL;
94
95         entry = talloc_zero(mem_ctx, struct gp_registry_entry);
96         NT_STATUS_HAVE_NO_MEMORY(entry);
97
98         data = talloc_zero(mem_ctx, struct registry_value);
99         NT_STATUS_HAVE_NO_MEMORY(data);
100
101         data->type = data_type;
102         data->data = *blob;
103
104         entry->key = key;
105         entry->data = data;
106         entry->action = action;
107         entry->value = talloc_strdup(mem_ctx, value);
108         NT_STATUS_HAVE_NO_MEMORY(entry->value);
109
110         *entry_out = entry;
111
112         return NT_STATUS_OK;
113 }
114
115 /****************************************************************
116 ****************************************************************/
117
118 static NTSTATUS scripts_parse_ini_section(struct gp_inifile_context *ini_ctx,
119                                           uint32_t flags,
120                                           const char *section,
121                                           struct gp_registry_entry **entries,
122                                           size_t *num_entries)
123 {
124         NTSTATUS status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
125         NTSTATUS result;
126         int i = 0;
127
128         while (1) {
129
130                 const char *key = NULL;
131                 const char *script = NULL;
132                 const char *count = NULL;
133                 const char *parameters = NULL;
134                 DATA_BLOB blob;
135                 bool ok;
136
137                 count = talloc_asprintf(ini_ctx->mem_ctx, "%d", i);
138                 NT_STATUS_HAVE_NO_MEMORY(count);
139
140                 key = talloc_asprintf(ini_ctx->mem_ctx, "%s:%s%s",
141                                       section, count,
142                                       GP_SCRIPTS_SECTION_CMDLINE);
143                 NT_STATUS_HAVE_NO_MEMORY(key);
144
145                 result = gp_inifile_getstring(ini_ctx, key, &script);
146                 if (!NT_STATUS_IS_OK(result)) {
147                         break;
148                 }
149
150                 key = talloc_asprintf(ini_ctx->mem_ctx, "%s:%s%s",
151                                       section, count,
152                                       GP_SCRIPTS_SECTION_PARAMETERS);
153                 NT_STATUS_HAVE_NO_MEMORY(key);
154
155                 result = gp_inifile_getstring(ini_ctx, key, &parameters);
156                 if (!NT_STATUS_IS_OK(result)) {
157                         break;
158                 }
159
160                 {
161                         struct gp_registry_entry *entry = NULL;
162
163                         ok = push_reg_sz(ini_ctx->mem_ctx, &blob, script);
164                         if (!ok) {
165                                 return NT_STATUS_NO_MEMORY;
166                         }
167
168                         status = generate_gp_registry_entry(ini_ctx->mem_ctx,
169                                                             count,
170                                                             GP_SCRIPTS_REG_VAL_SCRIPT,
171                                                             REG_SZ,
172                                                             &blob,
173                                                             GP_REG_ACTION_ADD_VALUE,
174                                                             &entry);
175                         NT_STATUS_NOT_OK_RETURN(status);
176                         if (!add_gp_registry_entry_to_array(ini_ctx->mem_ctx,
177                                                             entry,
178                                                             entries,
179                                                             num_entries)) {
180                                 return NT_STATUS_NO_MEMORY;
181                         }
182                 }
183                 {
184                         struct gp_registry_entry *entry = NULL;
185
186                         ok = push_reg_sz(ini_ctx->mem_ctx, &blob, parameters);
187                         if (!ok) {
188                                 return NT_STATUS_NO_MEMORY;
189                         }
190
191                         status = generate_gp_registry_entry(ini_ctx->mem_ctx,
192                                                             count,
193                                                             GP_SCRIPTS_REG_VAL_PARAMETERS,
194                                                             REG_SZ,
195                                                             &blob,
196                                                             GP_REG_ACTION_ADD_VALUE,
197                                                             &entry);
198                         NT_STATUS_NOT_OK_RETURN(status);
199                         if (!add_gp_registry_entry_to_array(ini_ctx->mem_ctx,
200                                                             entry,
201                                                             entries,
202                                                             num_entries)) {
203                                 return NT_STATUS_NO_MEMORY;
204                         }
205                 }
206                 {
207                         struct gp_registry_entry *entry = NULL;
208
209                         blob = data_blob_talloc_zero(ini_ctx->mem_ctx, 8);
210
211                         status = generate_gp_registry_entry(ini_ctx->mem_ctx,
212                                                             count,
213                                                             GP_SCRIPTS_REG_VAL_EXECTIME,
214                                                             REG_QWORD,
215                                                             &blob,
216                                                             GP_REG_ACTION_ADD_VALUE,
217                                                             &entry);
218                         NT_STATUS_NOT_OK_RETURN(status);
219                         if (!add_gp_registry_entry_to_array(ini_ctx->mem_ctx,
220                                                             entry,
221                                                             entries,
222                                                             num_entries)) {
223                                 return NT_STATUS_NO_MEMORY;
224                         }
225                 }
226                 status = NT_STATUS_OK;
227                 i++;
228         }
229
230         return status;
231 }
232
233 /****************************************************************
234 ****************************************************************/
235
236 static WERROR scripts_store_reg_gpovals(TALLOC_CTX *mem_ctx,
237                                         struct registry_key *key,
238                                         const struct GROUP_POLICY_OBJECT *gpo)
239 {
240         WERROR werr;
241
242         if (!key || !gpo) {
243                 return WERR_INVALID_PARAMETER;
244         }
245
246         werr = gp_store_reg_val_sz(mem_ctx, key, "DisplayName",
247                 gpo->display_name);
248         W_ERROR_NOT_OK_RETURN(werr);
249
250         werr = gp_store_reg_val_sz(mem_ctx, key, "FileSysPath",
251                 gpo->file_sys_path);
252         W_ERROR_NOT_OK_RETURN(werr);
253
254         werr = gp_store_reg_val_sz(mem_ctx, key, "GPO-ID",
255                 gpo->ds_path);
256         W_ERROR_NOT_OK_RETURN(werr);
257
258         werr = gp_store_reg_val_sz(mem_ctx, key, "GPOName",
259                 gpo->name);
260         W_ERROR_NOT_OK_RETURN(werr);
261
262         werr = gp_store_reg_val_sz(mem_ctx, key, "SOM-ID",
263                 gpo->link);
264         W_ERROR_NOT_OK_RETURN(werr);
265
266         return werr;
267 }
268
269 /****************************************************************
270 ****************************************************************/
271
272 static WERROR scripts_apply(TALLOC_CTX *mem_ctx,
273                             const struct security_token *token,
274                             struct registry_key *root_key,
275                             uint32_t flags,
276                             const char *section,
277                             const struct GROUP_POLICY_OBJECT *gpo,
278                             struct gp_registry_entry *entries,
279                             size_t num_entries)
280 {
281         struct gp_registry_context *reg_ctx = NULL;
282         WERROR werr;
283         size_t i;
284         const char *keystr = NULL;
285         int count = 0;
286
287         if (num_entries == 0) {
288                 return WERR_OK;
289         }
290
291 #if 0
292         if (flags & GPO_INFO_FLAG_MACHINE) {
293                 struct security_token *tmp_token;
294
295                 tmp_token = registry_create_system_token(mem_ctx);
296                 W_ERROR_HAVE_NO_MEMORY(tmp_token);
297
298                 werr = gp_init_reg_ctx(mem_ctx, KEY_HKLM, REG_KEY_WRITE,
299                                        tmp_token,
300                                        &reg_ctx);
301         } else {
302                 werr = gp_init_reg_ctx(mem_ctx, KEY_HKCU, REG_KEY_WRITE,
303                                        token,
304                                        &reg_ctx);
305         }
306         W_ERROR_NOT_OK_RETURN(werr);
307 #endif
308
309         keystr = talloc_asprintf(mem_ctx, "%s\\%s\\%d", KEY_GP_SCRIPTS,
310                                  section, count++);
311         W_ERROR_HAVE_NO_MEMORY(keystr);
312
313         reg_deletekey_recursive(root_key, keystr);
314
315         werr = gp_store_reg_subkey(mem_ctx, keystr,
316                                    root_key, &root_key);
317         if (!W_ERROR_IS_OK(werr)) {
318                 goto done;
319         }
320
321         werr = scripts_store_reg_gpovals(mem_ctx, root_key, gpo);
322         if (!W_ERROR_IS_OK(werr)) {
323                 goto done;
324         }
325
326         for (i=0; i<num_entries; i++) {
327
328                 werr = reg_apply_registry_entry(mem_ctx, root_key, reg_ctx,
329                                                 &(entries)[i],
330                                                 token, flags);
331                 if (!W_ERROR_IS_OK(werr)) {
332                         DEBUG(0,("failed to apply registry: %s\n",
333                                 win_errstr(werr)));
334                         goto done;
335                 }
336         }
337
338  done:
339         gp_free_reg_ctx(reg_ctx);
340         return werr;
341 }
342
343 /****************************************************************
344 ****************************************************************/
345
346 static NTSTATUS scripts_process_group_policy(TALLOC_CTX *mem_ctx,
347                                              uint32_t flags,
348                                              struct registry_key *root_key,
349                                              const struct security_token *token,
350                                              const struct GROUP_POLICY_OBJECT *deleted_gpo_list,
351                                              const struct GROUP_POLICY_OBJECT *changed_gpo_list)
352 {
353         NTSTATUS status;
354         WERROR werr;
355         int i = 0;
356         char *unix_path = NULL;
357         struct gp_inifile_context *ini_ctx = NULL;
358         struct gp_registry_entry *entries = NULL;
359         size_t num_entries = 0;
360         const char *list[] = {
361                 GP_SCRIPTS_INI_STARTUP,
362                 GP_SCRIPTS_INI_SHUTDOWN,
363                 GP_SCRIPTS_INI_LOGON,
364                 GP_SCRIPTS_INI_LOGOFF
365         };
366         const struct GROUP_POLICY_OBJECT *gpo;
367         char *gpo_cache_path = cache_path(GPO_CACHE_DIR);
368         if (gpo_cache_path == NULL) {
369                 return NT_STATUS_NO_MEMORY;
370         }
371
372         /* implementation of the policy callback function, see
373          * http://msdn.microsoft.com/en-us/library/aa373494%28v=vs.85%29.aspx
374          * for details - gd */
375
376         /* for now do not process the list of deleted group policies
377
378         for (gpo = deleted_gpo_list; gpo; gpo = gpo->next) {
379         }
380
381         */
382
383         for (gpo = changed_gpo_list; gpo; gpo = gpo->next) {
384
385                 gpext_debug_header(0, "scripts_process_group_policy", flags,
386                                    gpo, GP_EXT_GUID_SCRIPTS, NULL);
387
388                 status = gpo_get_unix_path(mem_ctx, gpo_cache_path,
389                                            gpo, &unix_path);
390                 if (!NT_STATUS_IS_OK(status)) {
391                         goto err_cache_path_free;
392                 }
393
394                 status = gp_inifile_init_context(mem_ctx, flags, unix_path,
395                                                  GP_SCRIPTS_INI, &ini_ctx);
396                 if (!NT_STATUS_IS_OK(status)) {
397                         goto err_cache_path_free;
398                 }
399
400                 for (i = 0; i < ARRAY_SIZE(list); i++) {
401
402                         TALLOC_FREE(entries);
403                         num_entries = 0;
404
405                         status = scripts_parse_ini_section(ini_ctx, flags, list[i],
406                                                            &entries, &num_entries);
407                         if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
408                                 continue;
409                         }
410
411                         if (!NT_STATUS_IS_OK(status)) {
412                                 TALLOC_FREE(ini_ctx);
413                                 goto err_cache_path_free;
414                         }
415
416                         dump_reg_entries(flags, "READ", entries, num_entries);
417
418                         werr = scripts_apply(ini_ctx->mem_ctx, token, root_key,
419                                              flags, list[i], gpo, entries, num_entries);
420                         if (!W_ERROR_IS_OK(werr)) {
421                                 continue; /* FIXME: finally fix storing emtpy strings and REG_QWORD! */
422                         }
423                 }
424
425                 TALLOC_FREE(ini_ctx);
426         }
427         status = NT_STATUS_OK;
428
429 err_cache_path_free:
430         talloc_free(gpo_cache_path);
431         return status;
432 }
433
434 /****************************************************************
435 ****************************************************************/
436
437 static NTSTATUS scripts_initialize(TALLOC_CTX *mem_ctx)
438 {
439         return NT_STATUS_OK;
440 }
441
442 /****************************************************************
443 ****************************************************************/
444
445 static NTSTATUS scripts_shutdown(void)
446 {
447         NTSTATUS status;
448
449         status = gpext_unregister_gp_extension(GP_EXT_NAME);
450         if (NT_STATUS_IS_OK(status)) {
451                 return status;
452         }
453
454         TALLOC_FREE(ctx);
455
456         return NT_STATUS_OK;
457 }
458
459 /****************************************************************
460 ****************************************************************/
461
462 static struct gp_extension_methods scripts_methods = {
463         .initialize             = scripts_initialize,
464         .process_group_policy   = scripts_process_group_policy,
465         .get_reg_config         = scripts_get_reg_config,
466         .shutdown               = scripts_shutdown
467 };
468
469 /****************************************************************
470 ****************************************************************/
471
472 NTSTATUS gpext_scripts_init(TALLOC_CTX *mem_ctx)
473 {
474         NTSTATUS status;
475
476         ctx = talloc_init("gpext_scripts_init");
477         NT_STATUS_HAVE_NO_MEMORY(ctx);
478
479         status = gpext_register_gp_extension(ctx, SMB_GPEXT_INTERFACE_VERSION,
480                                              GP_EXT_NAME, GP_EXT_GUID_SCRIPTS,
481                                              &scripts_methods);
482         if (!NT_STATUS_IS_OK(status)) {
483                 TALLOC_FREE(ctx);
484         }
485
486         return status;
487 }