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