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