s3:registry: make regdb_fetch_keys() static
[metze/samba/wip.git] / source3 / registry / reg_parse_internal.c
1 /*
2  * Unix SMB/CIFS implementation.
3  *
4  * Registry helper routines
5  *
6  * Copyright (C) Gregor Beck 2010
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 /**
22  * @file   reg_parse_internal.h
23  * @author Gregor Beck <gb@sernet.de>
24  * @date   Sep 2010
25  * @brief
26  */
27
28 #include "reg_parse_internal.h"
29 #include "cbuf.h"
30 #include "srprs.h"
31 #include "registry.h"
32
33 size_t iconvert_talloc(const void* ctx,
34                        smb_iconv_t cd,
35                        const char* src, size_t srclen,
36                        char** pdst)
37 {
38         size_t dstlen, ret;
39         size_t obytes, ibytes;
40         char *optr, *dst, *tmp;
41         const char* iptr;
42
43         if (cd == NULL || cd == ((smb_iconv_t)-1)) {
44                 return -1;
45         }
46
47         dst = *pdst;
48
49         if (dst == NULL) {
50                 /*
51                  * Allocate an extra two bytes for the
52                  * terminating zero.
53                  */
54                 dstlen = srclen + 2;
55                 dst = (char *)talloc_size(ctx, dstlen);
56                 if (dst == NULL) {
57                         DEBUG(0,("iconver_talloc no mem\n"));
58                         return -1;
59                 }
60         } else {
61                 dstlen = talloc_get_size(dst);
62         }
63 convert:
64         iptr   = src;
65         ibytes = srclen;
66         optr   = dst;
67         obytes = dstlen-2;
68
69         ret = smb_iconv(cd, &iptr, &ibytes, &optr, &obytes);
70
71         if(ret == -1) {
72                 const char *reason="unknown error";
73                 switch(errno) {
74                 case EINVAL:
75                         reason="Incomplete multibyte sequence";
76                         break;
77                 case E2BIG:
78                         dstlen = 2*dstlen + 2;
79                         tmp    = talloc_realloc(ctx, dst, char, dstlen);
80                         if (tmp == NULL) {
81                                 reason="talloc_realloc failed";
82                                 break;
83                         }
84                         dst = tmp;
85                         goto convert;
86                 case EILSEQ:
87                         reason="Illegal multibyte sequence";
88                         break;
89                 }
90                 DEBUG(0,("Conversion error: %s(%.80s) %li\n", reason, iptr,
91                          (long int)(iptr-src)));
92                 talloc_free(dst);
93                 return -1;
94         }
95
96         dstlen = (dstlen-2) - obytes;
97
98         SSVAL(dst, dstlen, 0);
99
100         *pdst = dst;
101         return dstlen;
102 }
103
104 #ifndef HKEY_CURRENT_CONFIG
105 #define HKEY_CURRENT_CONFIG             0x80000005
106 #endif
107 #ifndef HKEY_DYN_DATA
108 #define HKEY_DYN_DATA                   0x80000006
109 #endif
110 #ifndef HKEY_PERFORMANCE_TEXT
111 #define HKEY_PERFORMANCE_TEXT           0x80000050
112 #endif
113 #ifndef HKEY_PERFORMANCE_NLSTEXT
114 #define HKEY_PERFORMANCE_NLSTEXT        0x80000060
115 #endif
116
117 #define HIVE_INFO_ENTRY(SHORT,LONG)             \
118 const struct hive_info HIVE_INFO_##SHORT = {    \
119         .handle = LONG,                         \
120         .short_name = #SHORT,                   \
121         .short_name_len = sizeof(#SHORT)-1,     \
122         .long_name = #LONG,                     \
123         .long_name_len = sizeof(#LONG)-1,       \
124 }
125
126 HIVE_INFO_ENTRY(HKLM, HKEY_LOCAL_MACHINE);
127 HIVE_INFO_ENTRY(HKCU, HKEY_CURRENT_USER);
128 HIVE_INFO_ENTRY(HKCR, HKEY_CLASSES_ROOT);
129 HIVE_INFO_ENTRY(HKU , HKEY_USERS);
130 HIVE_INFO_ENTRY(HKCC, HKEY_CURRENT_CONFIG);
131 HIVE_INFO_ENTRY(HKDD, HKEY_DYN_DATA);
132 HIVE_INFO_ENTRY(HKPD, HKEY_PERFORMANCE_DATA);
133 HIVE_INFO_ENTRY(HKPT, HKEY_PERFORMANCE_TEXT);
134 HIVE_INFO_ENTRY(HKPN, HKEY_PERFORMANCE_NLSTEXT);
135 #undef HIVE_INFO_ENTRY
136
137 const struct hive_info* HIVE_INFO[] = {
138         &HIVE_INFO_HKLM, &HIVE_INFO_HKCU, &HIVE_INFO_HKCR, &HIVE_INFO_HKU,
139         &HIVE_INFO_HKCC, &HIVE_INFO_HKDD, &HIVE_INFO_HKPD, &HIVE_INFO_HKPT,
140         &HIVE_INFO_HKPN, NULL
141 };
142
143 #define TOINT(A,B) ((int)(A) << 8) + (int)(B)
144
145 bool srprs_hive(const char** ptr, const struct hive_info** result)
146 {
147         const char* str = *ptr;
148         const struct hive_info* info = NULL;
149         bool long_hive = false;
150
151         if ((toupper(str[0]) != 'H') || (toupper(str[1]) != 'K')
152             || (str[2] == '\0') )
153         {
154                 return false;
155         }
156
157         switch ( TOINT(toupper(str[2]), toupper(str[3])) ) {
158         case TOINT('E', 'Y'):
159                 if (str[4] == '_') {
160                         int i;
161                         for (i=0; (info = HIVE_INFO[i]); i++) {
162                                 if (strncmp(&str[5], &info->long_name[5],
163                                             info->long_name_len-5) == 0)
164                                 {
165                                         long_hive = true;
166                                         break;
167                                 }
168                         }
169                 }
170                 break;
171         case TOINT('L', 'M'):
172                 info = &HIVE_INFO_HKLM;
173                 break;
174         case TOINT('C', 'U'):
175                 info = &HIVE_INFO_HKCU;
176                 break;
177         case TOINT('C', 'R'):
178                 info = &HIVE_INFO_HKCR;
179                 break;
180         case TOINT('C', 'C'):
181                 info = &HIVE_INFO_HKCC;
182                 break;
183         case TOINT('D', 'D'):
184                 info = &HIVE_INFO_HKDD;
185                 break;
186         case TOINT('P', 'D'):
187                 info = &HIVE_INFO_HKPD;
188                 break;
189         case TOINT('P', 'T'):
190                 info = &HIVE_INFO_HKPT;
191                 break;
192         case TOINT('P', 'N'):
193                 info = &HIVE_INFO_HKPN;
194                 break;
195         default:
196                 if (toupper(str[2]) == 'U') {
197                         info = &HIVE_INFO_HKU;
198                 }
199                 break;
200         }
201         if (info != NULL) {
202                 if (result != NULL) {
203                         *result = info;
204                 }
205                 *ptr += long_hive ? info->long_name_len : info->short_name_len;
206                 return true;
207         }
208         return false;
209 }
210
211 const struct hive_info* hive_info(const char* name)
212 {
213         const struct hive_info* info = NULL;
214         srprs_hive(&name, &info);
215         return info;
216 }
217
218 const char* get_charset(const char* c)
219 {
220         if (strcmp(c, "dos") == 0) {
221                 return lp_dos_charset();
222         } else if (strcmp(c, "unix") == 0) {
223                 return lp_unix_charset();
224         } else {
225                 return c;
226         }
227 }
228
229 bool set_iconv(smb_iconv_t* t, const char* to, const char* from)
230 {
231         smb_iconv_t cd = (smb_iconv_t)-1;
232
233         if (to && from) {
234                 to   = get_charset(to);
235                 from = get_charset(from);
236                 cd   = smb_iconv_open(to, from);
237                 if (cd == ((smb_iconv_t)-1)) {
238                         return false;
239                 }
240         }
241         if ((*t != (smb_iconv_t)NULL) && (*t != (smb_iconv_t)-1)) {
242                 smb_iconv_close(*t);
243         }
244         *t = cd;
245         return true;
246 }
247
248 /**
249  * Parse option string
250  * @param[in,out] ptr parse position
251  * @param[in] mem_ctx talloc context
252  * @param[out] name ptr 2 value
253  * @param[out] value ptr 2 value
254  * @return true on success
255  */
256 bool srprs_option(const char** ptr, const void* mem_ctx, char** name, char** value)
257 {
258         const char* pos = *ptr;
259         void* ctx = talloc_new(mem_ctx);
260
261         cbuf* key = cbuf_new(ctx);
262         cbuf* val = NULL;
263
264         while(srprs_charsetinv(&pos, ",= \t\n\r", key))
265                 ;
266         if (pos == *ptr) {
267                 talloc_free(ctx);
268                 return false;
269         }
270
271         if (name != NULL) {
272                 *name = talloc_steal(mem_ctx, cbuf_gets(key, 0));
273         }
274
275         if (*pos == '=') {
276                 val = cbuf_new(ctx);
277                 pos++;
278                 if (!srprs_quoted_string(ptr, val, NULL)) {
279                         while(srprs_charsetinv(&pos, ", \t\n\r", val))
280                                 ;
281                 }
282                 if (value != NULL) {
283                         *value = talloc_steal(mem_ctx, cbuf_gets(val, 0));
284                 }
285         } else {
286                 if (value != NULL) {
287                         *value = NULL;
288                 }
289         }
290
291         while(srprs_char(&pos, ','))
292                 ;
293
294         *ptr = pos;
295         return true;
296 }
297
298 #define CH_INVALID ((charset_t)-1)
299 static const struct {
300         const char* const name;
301         charset_t ctype;
302         int  len;
303         char seq[4];
304 } BOM[] = {
305         {"UTF-8",    CH_UTF8,    3, {0xEF, 0xBB, 0xBF}},
306         {"UTF-32LE", CH_INVALID, 4, {0xFF, 0xFE, 0x00, 0x00}},
307         {"UTF-16LE", CH_UTF16LE, 2, {0xFF, 0xFE}},
308         {"UTF-16BE", CH_UTF16BE, 2, {0xFE, 0xFF}},
309         {"UTF-32BE", CH_INVALID, 4, {0x00, 0x00, 0xFE, 0xFF}},
310         {NULL,       CH_INVALID, 0}
311 };
312
313 bool srprs_bom(const char** ptr, const char** name, charset_t* ctype)
314 {
315         int i;
316         for (i=0; BOM[i].name; i++) {
317                 if (memcmp(*ptr, BOM[i].seq, BOM[i].len) == 0) {
318                         break;
319                 }
320         }
321
322         if (BOM[i].name != NULL) {
323                 DEBUG(0, ("Found Byte Order Mark for : %s\n", BOM[i].name));
324
325                 if (name != NULL) {
326                         *name  = BOM[i].name;
327                 }
328
329                 if (ctype != NULL) {
330                         *ctype = BOM[i].ctype;
331                 }
332
333                 *ptr  += BOM[i].len;
334
335                 return true;
336         }
337         return false;
338 }
339
340 int write_bom(FILE* file, const char* charset, charset_t ctype)
341 {
342         int i;
343         if ( charset == NULL ) {
344                 for (i=0; BOM[i].name; i++) {
345                         if (BOM[i].ctype == ctype) {
346                                 return fwrite(BOM[i].seq, 1, BOM[i].len, file);
347                         }
348                 }
349                 DEBUG(0, ("No Byte Order Mark for charset_t: %u\n", (unsigned)ctype));
350         } else {
351                 for (i=0; BOM[i].name; i++) {
352                         if (strcasecmp_m(BOM[i].name, charset) == 0) {
353                                 return fwrite(BOM[i].seq, 1, BOM[i].len, file);
354                         }
355                 }
356                 DEBUG(0, ("No Byte Order Mark for charset_t: %s\n", charset));
357         }
358         return 0;
359 }
360
361
362 int cbuf_puts_case(cbuf* s, const char* str, size_t len, enum fmt_case fmt)
363 {
364         size_t pos = cbuf_getpos(s);
365         int ret = cbuf_puts(s, str, len);
366         char* ptr = cbuf_gets(s,pos);
367
368         if (ret <= 0) {
369                 return ret;
370         }
371
372         switch (fmt) {
373         case FMT_CASE_PRESERVE:
374                 break;
375         case FMT_CASE_UPPER:
376                 while(*ptr != '\0') {
377                         *ptr = toupper(*ptr);
378                         ptr++;
379                 }
380                 break;
381         case FMT_CASE_TITLE:
382                 *ptr = toupper(*ptr);
383                 ptr++;
384         case FMT_CASE_LOWER:
385                 while(*ptr != '\0') {
386                         *ptr = tolower(*ptr);
387                         ptr++;
388                 }
389         }
390         return ret;
391 }