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