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