libcli/security Provide a common, top level libcli/security/security.h
[samba.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 "gpo.h"
23 #include "gpo_ini.h"
24 #include "system/filesys.h"
25
26
27 static bool change_section(const char *section, void *ctx_ptr)
28 {
29         struct gp_inifile_context *ctx = (struct gp_inifile_context *) ctx_ptr;
30
31         if (ctx->current_section) {
32                 talloc_free(ctx->current_section);
33         }
34         ctx->current_section = talloc_strdup(ctx, section);
35         return true;
36 }
37
38 /****************************************************************
39 ****************************************************************/
40
41 static bool store_keyval_pair(const char *key, const char *value, void *ctx_ptr)
42 {
43         struct gp_inifile_context *ctx = (struct gp_inifile_context *) ctx_ptr;
44         ctx->data = talloc_realloc(ctx, ctx->data, struct keyval_pair *, ctx->keyval_count+1);
45         ctx->data[ctx->keyval_count] = talloc_zero(ctx, struct keyval_pair);
46         ctx->data[ctx->keyval_count]->key = talloc_asprintf(ctx, "%s:%s", ctx->current_section, key);
47         ctx->data[ctx->keyval_count]->val = talloc_strdup(ctx, value);
48         ctx->keyval_count++;
49         return true;
50 }
51
52 /****************************************************************
53 ****************************************************************/
54
55 static NTSTATUS convert_file_from_ucs2(TALLOC_CTX *mem_ctx,
56                                        const char *filename_in,
57                                        char **filename_out)
58 {
59         int tmp_fd = -1;
60         uint8_t *data_in = NULL;
61         uint8_t *data_out = NULL;
62         char *tmp_name = NULL;
63         NTSTATUS status;
64         size_t n = 0;
65         size_t converted_size;
66
67         if (!filename_out) {
68                 return NT_STATUS_INVALID_PARAMETER;
69         }
70
71         data_in = (uint8_t *)file_load(filename_in, &n, 0, NULL);
72         if (!data_in) {
73                 status = NT_STATUS_NO_SUCH_FILE;
74                 goto out;
75         }
76
77         tmp_name = talloc_asprintf(mem_ctx, "%s/convert_file_from_ucs2.XXXXXX",
78                 tmpdir());
79         if (!tmp_name) {
80                 status = NT_STATUS_NO_MEMORY;
81                 goto out;
82         }
83
84         tmp_fd = mkstemp(tmp_name);
85         if (tmp_fd == -1) {
86                 status = NT_STATUS_ACCESS_DENIED;
87                 goto out;
88         }
89
90         if (!convert_string_talloc(mem_ctx, CH_UTF16LE, CH_UNIX, data_in, n,
91                                    (void *)&data_out, &converted_size, false))
92         {
93                 status = NT_STATUS_INVALID_BUFFER_SIZE;
94                 goto out;
95         }
96
97         /* skip utf8 BOM */
98         DEBUG(11,("convert_file_from_ucs2: "
99                "data_out[0]: 0x%x, data_out[1]: 0x%x, data_out[2]: 0x%x\n",
100                 data_out[0], data_out[1], data_out[2]));
101
102         if ((data_out[0] == 0xef) && (data_out[1] == 0xbb) &&
103             (data_out[2] == 0xbf)) {
104                 DEBUG(11,("convert_file_from_ucs2: "
105                          "%s skipping utf8 BOM\n", tmp_name));
106                 data_out += 3;
107                 converted_size -= 3;
108         }
109
110         if (write(tmp_fd, data_out, converted_size) != converted_size) {
111                 status = map_nt_error_from_unix(errno);
112                 goto out;
113         }
114
115         *filename_out = tmp_name;
116
117         status = NT_STATUS_OK;
118
119  out:
120         if (tmp_fd != -1) {
121                 close(tmp_fd);
122         }
123
124         talloc_free(data_in);
125
126         return status;
127 }
128
129 /****************************************************************
130 ****************************************************************/
131
132 NTSTATUS gp_inifile_getstring(struct gp_inifile_context *ctx, const char *key, char **ret)
133 {
134         int i;
135
136         for (i = 0; i < ctx->keyval_count; i++) {
137                 if (strcmp(ctx->data[i]->key, key) == 0) {
138                         *ret = ctx->data[i]->val;
139                         return NT_STATUS_OK;
140                 }
141         }
142         return NT_STATUS_NOT_FOUND;
143 }
144
145 /****************************************************************
146 ****************************************************************/
147
148 NTSTATUS gp_inifile_getint(struct gp_inifile_context *ctx, const char *key, int *ret)
149 {
150         char *value;
151         NTSTATUS result;
152
153         result = gp_inifile_getstring(ctx,key, &value);
154         if (!NT_STATUS_IS_OK(result)) {
155                 return result;
156         }
157
158         *ret = (int)strtol(value, NULL, 10);
159         return NT_STATUS_OK;
160 }
161
162 /****************************************************************
163 ****************************************************************/
164
165 NTSTATUS gp_inifile_init_context(TALLOC_CTX *mem_ctx,
166                                  uint32_t flags,
167                                  const char *unix_path,
168                                  const char *suffix,
169                                  struct gp_inifile_context **ctx_ret)
170 {
171         struct gp_inifile_context *ctx = NULL;
172         NTSTATUS status;
173         int rv;
174         char *tmp_filename = NULL;
175         const char *ini_filename = NULL;
176
177         if (!unix_path || !ctx_ret) {
178                 return NT_STATUS_INVALID_PARAMETER;
179         }
180
181         ctx = talloc_zero(mem_ctx, struct gp_inifile_context);
182         NT_STATUS_HAVE_NO_MEMORY(ctx);
183
184         status = gp_find_file(mem_ctx, flags, unix_path, suffix,
185                               &ini_filename);
186
187         if (!NT_STATUS_IS_OK(status)) {
188                 goto failed;
189         }
190
191         status = convert_file_from_ucs2(mem_ctx, ini_filename,
192                                         &tmp_filename);
193         if (!NT_STATUS_IS_OK(status)) {
194                 goto failed;
195         }
196
197         rv = pm_process(tmp_filename, change_section, store_keyval_pair, ctx);
198         if (!rv) {
199                 return NT_STATUS_NO_SUCH_FILE;
200         }
201
202
203         ctx->generated_filename = tmp_filename;
204         ctx->mem_ctx = mem_ctx;
205
206         *ctx_ret = ctx;
207
208         return NT_STATUS_OK;
209
210  failed:
211
212         DEBUG(1,("gp_inifile_init_context failed: %s\n",
213                 nt_errstr(status)));
214
215         talloc_free(ctx);
216
217         return status;
218 }
219
220 /****************************************************************
221  parse the local gpt.ini file
222 ****************************************************************/
223
224 #define GPT_INI_SECTION_GENERAL "General"
225 #define GPT_INI_PARAMETER_VERSION "Version"
226 #define GPT_INI_PARAMETER_DISPLAYNAME "displayName"
227
228 NTSTATUS parse_gpt_ini(TALLOC_CTX *mem_ctx,
229                        const char *filename,
230                        uint32_t *version,
231                        char **display_name)
232 {
233         NTSTATUS result;
234         int rv;
235         int v = 0;
236         char *name = NULL;
237         struct gp_inifile_context *ctx;
238
239         if (!filename) {
240                 return NT_STATUS_INVALID_PARAMETER;
241         }
242
243         ctx = talloc_zero(mem_ctx, struct gp_inifile_context);
244         NT_STATUS_HAVE_NO_MEMORY(ctx);
245
246         rv = pm_process(filename, change_section, store_keyval_pair, ctx);
247         if (!rv) {
248                 return NT_STATUS_NO_SUCH_FILE;
249         }
250
251
252         result = gp_inifile_getstring(ctx, GPT_INI_SECTION_GENERAL
253                         ":"GPT_INI_PARAMETER_DISPLAYNAME, &name);
254         if (!NT_STATUS_IS_OK(result)) {
255                 /* the default domain policy and the default domain controller
256                  * policy never have a displayname in their gpt.ini file */
257                 DEBUG(10,("parse_gpt_ini: no name in %s\n", filename));
258         }
259
260         if (name && display_name) {
261                 *display_name = talloc_strdup(ctx, name);
262                 if (*display_name == NULL) {
263                         return NT_STATUS_NO_MEMORY;
264                 }
265         }
266
267         result = gp_inifile_getint(ctx, GPT_INI_SECTION_GENERAL
268                         ":"GPT_INI_PARAMETER_VERSION, &v);
269         if (!NT_STATUS_IS_OK(result)) {
270                 DEBUG(10,("parse_gpt_ini: no version\n"));
271                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
272         }
273
274         if (version) {
275                 *version = v;
276         }
277
278         talloc_free(ctx);
279
280         return NT_STATUS_OK;
281 }