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