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