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