Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : * Group Policy Support
4 : * Copyright (C) Guenther Deschner 2007
5 : * Copyright (C) Wilco Baan Hofman 2009
6 : *
7 : * This program is free software; you can redistribute it and/or modify
8 : * it under the terms of the GNU General Public License as published by
9 : * the Free Software Foundation; either version 3 of the License, or
10 : * (at your option) any later version.
11 : *
12 : * This program is distributed in the hope that it will be useful,
13 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : * GNU General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU General Public License
18 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "includes.h"
22 : #include "gpo.h"
23 : #include "gpo_ini.h"
24 : #include "system/filesys.h"
25 :
26 :
27 0 : static bool change_section(const char *section, void *ctx_ptr)
28 : {
29 0 : struct gp_inifile_context *ctx = (struct gp_inifile_context *) ctx_ptr;
30 :
31 0 : if (ctx->current_section) {
32 0 : talloc_free(ctx->current_section);
33 : }
34 0 : ctx->current_section = talloc_strdup(ctx, section);
35 0 : if (!ctx->current_section) {
36 0 : return false;
37 : }
38 0 : return true;
39 : }
40 :
41 : /****************************************************************
42 : ****************************************************************/
43 :
44 0 : static bool store_keyval_pair(const char *key, const char *value, void *ctx_ptr)
45 : {
46 0 : struct gp_inifile_context *ctx = (struct gp_inifile_context *) ctx_ptr;
47 :
48 0 : ctx->data = talloc_realloc(ctx, ctx->data, struct keyval_pair *, ctx->keyval_count+1);
49 0 : if (!ctx->data) {
50 0 : return false;
51 : }
52 :
53 0 : ctx->data[ctx->keyval_count] = talloc_zero(ctx, struct keyval_pair);
54 0 : if (!ctx->data[ctx->keyval_count]) {
55 0 : return false;
56 : }
57 :
58 0 : ctx->data[ctx->keyval_count]->key = talloc_asprintf(ctx, "%s:%s", ctx->current_section, key);
59 0 : ctx->data[ctx->keyval_count]->val = talloc_strdup(ctx, value ? value : "");
60 :
61 0 : if (!ctx->data[ctx->keyval_count]->key ||
62 0 : !ctx->data[ctx->keyval_count]->val) {
63 0 : return false;
64 : }
65 :
66 0 : ctx->keyval_count++;
67 0 : return true;
68 : }
69 :
70 : /****************************************************************
71 : ****************************************************************/
72 :
73 0 : static NTSTATUS convert_file_from_ucs2(TALLOC_CTX *mem_ctx,
74 : const char *filename_in,
75 : char **filename_out)
76 : {
77 0 : int tmp_fd = -1;
78 0 : uint8_t *data_in = NULL;
79 0 : uint8_t *data_out = NULL;
80 0 : char *tmp_name = NULL;
81 : NTSTATUS status;
82 0 : size_t n = 0;
83 : size_t converted_size;
84 : mode_t mask;
85 :
86 0 : if (!filename_out) {
87 0 : return NT_STATUS_INVALID_PARAMETER;
88 : }
89 :
90 0 : data_in = (uint8_t *)file_load(filename_in, &n, 0, mem_ctx);
91 0 : if (!data_in) {
92 0 : status = NT_STATUS_NO_SUCH_FILE;
93 0 : goto out;
94 : }
95 :
96 0 : DEBUG(11,("convert_file_from_ucs2: "
97 : "data_in[0]: 0x%x, data_in[1]: 0x%x, data_in[2]: 0x%x\n",
98 : data_in[0], data_in[1], data_in[2]));
99 :
100 0 : if ((data_in[0] != 0xff) || (data_in[1] != 0xfe) || (data_in[2] != 0x0d)) {
101 0 : *filename_out = NULL;
102 0 : status = NT_STATUS_OK;
103 0 : goto out;
104 : }
105 :
106 0 : tmp_name = talloc_asprintf(mem_ctx, "%s/convert_file_from_ucs2.XXXXXX",
107 : tmpdir());
108 0 : if (!tmp_name) {
109 0 : status = NT_STATUS_NO_MEMORY;
110 0 : goto out;
111 : }
112 :
113 0 : mask = umask(S_IRWXO | S_IRWXG);
114 0 : tmp_fd = mkstemp(tmp_name);
115 0 : umask(mask);
116 0 : if (tmp_fd == -1) {
117 0 : status = NT_STATUS_ACCESS_DENIED;
118 0 : goto out;
119 : }
120 :
121 0 : if (!convert_string_talloc(mem_ctx, CH_UTF16LE, CH_UNIX, data_in, n,
122 : (void *)&data_out, &converted_size))
123 : {
124 0 : status = NT_STATUS_INVALID_BUFFER_SIZE;
125 0 : goto out;
126 : }
127 :
128 0 : DEBUG(11,("convert_file_from_ucs2: "
129 : "%s skipping utf16-le BOM\n", tmp_name));
130 :
131 0 : converted_size -= 3;
132 :
133 0 : if (write(tmp_fd, data_out + 3, converted_size) != converted_size) {
134 0 : status = map_nt_error_from_unix_common(errno);
135 0 : goto out;
136 : }
137 :
138 0 : *filename_out = tmp_name;
139 :
140 0 : status = NT_STATUS_OK;
141 :
142 0 : out:
143 0 : if (tmp_fd != -1) {
144 0 : close(tmp_fd);
145 : }
146 :
147 0 : talloc_free(data_in);
148 0 : talloc_free(data_out);
149 :
150 0 : return status;
151 : }
152 :
153 : /****************************************************************
154 : ****************************************************************/
155 :
156 0 : NTSTATUS gp_inifile_getstring(struct gp_inifile_context *ctx, const char *key, const char **ret)
157 : {
158 : int i;
159 :
160 0 : for (i = 0; i < ctx->keyval_count; i++) {
161 0 : if (strcmp(ctx->data[i]->key, key) == 0) {
162 0 : if (ret) {
163 0 : *ret = ctx->data[i]->val;
164 : }
165 0 : return NT_STATUS_OK;
166 : }
167 : }
168 0 : return NT_STATUS_NOT_FOUND;
169 : }
170 :
171 : /****************************************************************
172 : ****************************************************************/
173 :
174 0 : NTSTATUS gp_inifile_getint(struct gp_inifile_context *ctx, const char *key, int *ret)
175 : {
176 : const char *value;
177 : NTSTATUS result;
178 :
179 0 : result = gp_inifile_getstring(ctx,key, &value);
180 0 : if (!NT_STATUS_IS_OK(result)) {
181 0 : return result;
182 : }
183 :
184 0 : if (ret) {
185 0 : *ret = (int)strtol(value, NULL, 10);
186 : }
187 0 : return NT_STATUS_OK;
188 : }
189 :
190 : /****************************************************************
191 : ****************************************************************/
192 :
193 0 : NTSTATUS gp_inifile_getbool(struct gp_inifile_context *ctx, const char *key, bool *ret)
194 : {
195 : const char *value;
196 : NTSTATUS result;
197 :
198 0 : result = gp_inifile_getstring(ctx,key, &value);
199 0 : if (!NT_STATUS_IS_OK(result)) {
200 0 : return result;
201 : }
202 :
203 0 : if (strequal(value, "Yes") ||
204 0 : strequal(value, "True")) {
205 0 : if (ret) {
206 0 : *ret = true;
207 : }
208 0 : return NT_STATUS_OK;
209 0 : } else if (strequal(value, "No") ||
210 0 : strequal(value, "False")) {
211 0 : if (ret) {
212 0 : *ret = false;
213 : }
214 0 : return NT_STATUS_OK;
215 : }
216 :
217 0 : return NT_STATUS_NOT_FOUND;
218 : }
219 :
220 : /****************************************************************
221 : ****************************************************************/
222 :
223 0 : NTSTATUS gp_inifile_enum_section(struct gp_inifile_context *ctx,
224 : const char *section,
225 : size_t *num_ini_keys,
226 : const char ***ini_keys,
227 : const char ***ini_values)
228 : {
229 : NTSTATUS status;
230 : int i;
231 0 : size_t num_keys = 0, num_vals = 0;
232 0 : const char **keys = NULL;
233 0 : const char **values = NULL;
234 :
235 0 : if (section == NULL || num_ini_keys == NULL ||
236 0 : ini_keys == NULL || ini_values == NULL) {
237 0 : return NT_STATUS_INVALID_PARAMETER;
238 : }
239 :
240 0 : for (i = 0; i < ctx->keyval_count; i++) {
241 :
242 : bool ok;
243 :
244 : /*
245 : * section: KEYNAME
246 : * KEYNAME:value matches
247 : * KEYNAME_OEM:value not
248 : */
249 :
250 0 : if (strlen(section)+1 > strlen(ctx->data[i]->key)) {
251 0 : continue;
252 : }
253 :
254 0 : if (!strnequal(section, ctx->data[i]->key, strlen(section))) {
255 0 : continue;
256 : }
257 :
258 0 : if (ctx->data[i]->key[strlen(section)] != ':') {
259 0 : continue;
260 : }
261 :
262 0 : ok = add_string_to_array(ctx, ctx->data[i]->key, &keys, &num_keys);
263 0 : if (!ok) {
264 0 : status = NT_STATUS_NO_MEMORY;
265 0 : goto failed;
266 : }
267 :
268 0 : ok = add_string_to_array(ctx, ctx->data[i]->val, &values, &num_vals);
269 0 : if (!ok) {
270 0 : status = NT_STATUS_NO_MEMORY;
271 0 : goto failed;
272 : }
273 :
274 0 : if (num_keys != num_vals) {
275 0 : status = NT_STATUS_INTERNAL_DB_CORRUPTION;
276 0 : goto failed;
277 : }
278 : }
279 :
280 0 : *num_ini_keys = num_keys;
281 0 : *ini_keys = keys;
282 0 : *ini_values = values;
283 :
284 0 : return NT_STATUS_OK;
285 :
286 0 : failed:
287 0 : talloc_free(keys);
288 0 : talloc_free(values);
289 :
290 0 : return status;
291 : }
292 :
293 :
294 : /****************************************************************
295 : ****************************************************************/
296 :
297 0 : NTSTATUS gp_inifile_init_context(TALLOC_CTX *mem_ctx,
298 : uint32_t flags,
299 : const char *unix_path,
300 : const char *suffix,
301 : struct gp_inifile_context **ctx_ret)
302 : {
303 0 : struct gp_inifile_context *ctx = NULL;
304 : NTSTATUS status;
305 : int rv;
306 0 : char *tmp_filename = NULL;
307 0 : const char *ini_filename = NULL;
308 :
309 0 : if (!unix_path || !ctx_ret) {
310 0 : return NT_STATUS_INVALID_PARAMETER;
311 : }
312 :
313 0 : ctx = talloc_zero(mem_ctx, struct gp_inifile_context);
314 0 : NT_STATUS_HAVE_NO_MEMORY(ctx);
315 :
316 0 : status = gp_find_file(mem_ctx, flags, unix_path, suffix,
317 : &ini_filename);
318 :
319 0 : if (!NT_STATUS_IS_OK(status)) {
320 0 : goto failed;
321 : }
322 :
323 0 : status = convert_file_from_ucs2(mem_ctx, ini_filename,
324 : &tmp_filename);
325 0 : if (!NT_STATUS_IS_OK(status)) {
326 0 : goto failed;
327 : }
328 :
329 0 : rv = pm_process(tmp_filename != NULL ? tmp_filename : ini_filename,
330 : change_section, store_keyval_pair, ctx);
331 0 : if (!rv) {
332 0 : return NT_STATUS_NO_SUCH_FILE;
333 : }
334 :
335 :
336 0 : ctx->generated_filename = tmp_filename;
337 0 : ctx->mem_ctx = mem_ctx;
338 :
339 0 : *ctx_ret = ctx;
340 :
341 0 : return NT_STATUS_OK;
342 :
343 0 : failed:
344 :
345 0 : DEBUG(1,("gp_inifile_init_context failed: %s\n",
346 : nt_errstr(status)));
347 :
348 0 : talloc_free(ctx);
349 :
350 0 : return status;
351 : }
352 :
353 : /****************************************************************
354 : ****************************************************************/
355 :
356 0 : NTSTATUS gp_inifile_init_context_direct(TALLOC_CTX *mem_ctx,
357 : const char *unix_path,
358 : struct gp_inifile_context **pgp_ctx)
359 : {
360 0 : struct gp_inifile_context *gp_ctx = NULL;
361 : NTSTATUS status;
362 : bool rv;
363 0 : char *tmp_filename = NULL;
364 :
365 0 : if (unix_path == NULL || pgp_ctx == NULL) {
366 0 : return NT_STATUS_INVALID_PARAMETER;
367 : }
368 :
369 0 : gp_ctx = talloc_zero(mem_ctx, struct gp_inifile_context);
370 0 : if (gp_ctx == NULL) {
371 0 : return NT_STATUS_NO_MEMORY;
372 : }
373 :
374 0 : status = convert_file_from_ucs2(mem_ctx, unix_path,
375 : &tmp_filename);
376 0 : if (!NT_STATUS_IS_OK(status)) {
377 0 : goto failed;
378 : }
379 :
380 0 : rv = pm_process_with_flags(tmp_filename != NULL ? tmp_filename : unix_path,
381 : true,
382 : change_section,
383 : store_keyval_pair,
384 : gp_ctx);
385 0 : if (!rv) {
386 0 : return NT_STATUS_NO_SUCH_FILE;
387 : }
388 :
389 0 : gp_ctx->generated_filename = tmp_filename;
390 0 : gp_ctx->mem_ctx = mem_ctx;
391 :
392 0 : *pgp_ctx = gp_ctx;
393 :
394 0 : return NT_STATUS_OK;
395 :
396 0 : failed:
397 :
398 0 : DEBUG(1,("gp_inifile_init_context_direct failed: %s\n",
399 : nt_errstr(status)));
400 :
401 0 : talloc_free(gp_ctx);
402 :
403 0 : return status;
404 : }
405 :
406 :
407 : /****************************************************************
408 : parse the local gpt.ini file
409 : ****************************************************************/
410 :
411 : #define GPT_INI_SECTION_GENERAL "General"
412 : #define GPT_INI_PARAMETER_VERSION "Version"
413 : #define GPT_INI_PARAMETER_DISPLAYNAME "displayName"
414 :
415 0 : NTSTATUS parse_gpt_ini(TALLOC_CTX *mem_ctx,
416 : const char *filename,
417 : uint32_t *version,
418 : char **display_name)
419 : {
420 : NTSTATUS result;
421 : int rv;
422 0 : int v = 0;
423 0 : const char *name = NULL;
424 : struct gp_inifile_context *ctx;
425 :
426 0 : if (!filename) {
427 0 : return NT_STATUS_INVALID_PARAMETER;
428 : }
429 :
430 0 : ctx = talloc_zero(mem_ctx, struct gp_inifile_context);
431 0 : NT_STATUS_HAVE_NO_MEMORY(ctx);
432 :
433 0 : rv = pm_process(filename, change_section, store_keyval_pair, ctx);
434 0 : if (!rv) {
435 0 : return NT_STATUS_NO_SUCH_FILE;
436 : }
437 :
438 :
439 0 : result = gp_inifile_getstring(ctx, GPT_INI_SECTION_GENERAL
440 : ":"GPT_INI_PARAMETER_DISPLAYNAME, &name);
441 0 : if (!NT_STATUS_IS_OK(result)) {
442 : /* the default domain policy and the default domain controller
443 : * policy never have a displayname in their gpt.ini file */
444 0 : DEBUG(10,("parse_gpt_ini: no name in %s\n", filename));
445 : }
446 :
447 0 : if (name && display_name) {
448 0 : *display_name = talloc_strdup(ctx, name);
449 0 : if (*display_name == NULL) {
450 0 : return NT_STATUS_NO_MEMORY;
451 : }
452 : }
453 :
454 0 : result = gp_inifile_getint(ctx, GPT_INI_SECTION_GENERAL
455 : ":"GPT_INI_PARAMETER_VERSION, &v);
456 0 : if (!NT_STATUS_IS_OK(result)) {
457 0 : DEBUG(10,("parse_gpt_ini: no version\n"));
458 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
459 : }
460 :
461 0 : if (version) {
462 0 : *version = v;
463 : }
464 :
465 0 : talloc_free(ctx);
466 :
467 0 : return NT_STATUS_OK;
468 : }
|