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