18914cab3d909e362f8f187a9a4bb33a1743d361
[gd/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 = gpext_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 *deleted_gpo_list,
343                                              struct GROUP_POLICY_OBJECT *changed_gpo_list,
344                                              const char *extension_guid,
345                                              const char *snapin_guid)
346 {
347         NTSTATUS status;
348         WERROR werr;
349         int i = 0;
350         char *unix_path = NULL;
351         struct gp_inifile_context *ini_ctx = NULL;
352         struct gp_registry_entry *entries = NULL;
353         size_t num_entries = 0;
354         const char *list[] = {
355                 GP_SCRIPTS_INI_STARTUP,
356                 GP_SCRIPTS_INI_SHUTDOWN,
357                 GP_SCRIPTS_INI_LOGON,
358                 GP_SCRIPTS_INI_LOGOFF
359         };
360         struct GROUP_POLICY_OBJECT *gpo;
361
362         /* implementation of the policy callback function, see
363          * http://msdn.microsoft.com/en-us/library/aa373494%28v=vs.85%29.aspx
364          * for details - gd */
365
366         /* for now do not process the list of deleted group policies
367
368         for (gpo = deleted_gpo_list; gpo; gpo = gpo->next) {
369         }
370
371         */
372
373         for (gpo = changed_gpo_list; gpo; gpo = gpo->next) {
374
375                 gpext_debug_header(0, "scripts_process_group_policy", flags,
376                                    gpo, extension_guid, snapin_guid);
377
378                 status = gpo_get_unix_path(mem_ctx, cache_path(GPO_CACHE_DIR),
379                                            gpo, &unix_path);
380                 NT_STATUS_NOT_OK_RETURN(status);
381
382                 status = gp_inifile_init_context(mem_ctx, flags, unix_path,
383                                                  GP_SCRIPTS_INI, &ini_ctx);
384                 NT_STATUS_NOT_OK_RETURN(status);
385
386                 for (i = 0; i < ARRAY_SIZE(list); i++) {
387
388                         TALLOC_FREE(entries);
389                         num_entries = 0;
390
391                         status = scripts_parse_ini_section(ini_ctx, flags, list[i],
392                                                            &entries, &num_entries);
393                         if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
394                                 continue;
395                         }
396
397                         if (!NT_STATUS_IS_OK(status)) {
398                                 return status;
399                         }
400
401                         dump_reg_entries(flags, "READ", entries, num_entries);
402
403                         werr = scripts_apply(ini_ctx->mem_ctx, token, root_key,
404                                              flags, list[i], gpo, entries, num_entries);
405                         if (!W_ERROR_IS_OK(werr)) {
406                                 continue; /* FIXME: finally fix storing emtpy strings and REG_QWORD! */
407                                 TALLOC_FREE(ini_ctx);
408                                 return werror_to_ntstatus(werr);
409                         }
410                 }
411
412                 TALLOC_FREE(ini_ctx);
413         }
414
415         return NT_STATUS_OK;
416 }
417
418 /****************************************************************
419 ****************************************************************/
420
421 static NTSTATUS scripts_initialize(TALLOC_CTX *mem_ctx)
422 {
423         return NT_STATUS_OK;
424 }
425
426 /****************************************************************
427 ****************************************************************/
428
429 static NTSTATUS scripts_shutdown(void)
430 {
431         NTSTATUS status;
432
433         status = gpext_unregister_gp_extension(GP_EXT_NAME);
434         if (NT_STATUS_IS_OK(status)) {
435                 return status;
436         }
437
438         TALLOC_FREE(ctx);
439
440         return NT_STATUS_OK;
441 }
442
443 /****************************************************************
444 ****************************************************************/
445
446 static struct gp_extension_methods scripts_methods = {
447         .initialize             = scripts_initialize,
448         .process_group_policy   = scripts_process_group_policy,
449         .get_reg_config         = scripts_get_reg_config,
450         .shutdown               = scripts_shutdown
451 };
452
453 /****************************************************************
454 ****************************************************************/
455
456 NTSTATUS gpext_scripts_init(void)
457 {
458         NTSTATUS status;
459
460         ctx = talloc_init("gpext_scripts_init");
461         NT_STATUS_HAVE_NO_MEMORY(ctx);
462
463         status = gpext_register_gp_extension(ctx, SMB_GPEXT_INTERFACE_VERSION,
464                                              GP_EXT_NAME, GP_EXT_GUID_SCRIPTS,
465                                              &scripts_methods);
466         if (!NT_STATUS_IS_OK(status)) {
467                 TALLOC_FREE(ctx);
468         }
469
470         return status;
471 }