/* * Unix SMB/CIFS implementation. * * Registry helper routines * * Copyright (C) Gregor Beck 2010 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /** * @file reg_parse_internal.h * @author Gregor Beck * @date Sep 2010 * @brief */ #include "reg_parse_internal.h" #include "cbuf.h" #include "srprs.h" #include "registry.h" size_t iconvert_talloc(const void* ctx, smb_iconv_t cd, const char* src, size_t srclen, char** pdst) { size_t dstlen, ret; size_t obytes, ibytes; char *optr, *dst, *tmp; const char* iptr; if (cd == NULL || cd == ((smb_iconv_t)-1)) { return -1; } dst = *pdst; if (dst == NULL) { /* * Allocate an extra two bytes for the * terminating zero. */ dstlen = srclen + 2; dst = (char *)talloc_size(ctx, dstlen); if (dst == NULL) { DEBUG(0,("iconver_talloc no mem\n")); return -1; } } else { dstlen = talloc_get_size(dst); } convert: iptr = src; ibytes = srclen; optr = dst; obytes = dstlen-2; ret = smb_iconv(cd, &iptr, &ibytes, &optr, &obytes); if(ret == -1) { const char *reason="unknown error"; switch(errno) { case EINVAL: reason="Incomplete multibyte sequence"; break; case E2BIG: dstlen = 2*dstlen + 2; tmp = talloc_realloc(ctx, dst, char, dstlen); if (tmp == NULL) { reason="talloc_realloc failed"; break; } dst = tmp; goto convert; case EILSEQ: reason="Illegal multibyte sequence"; break; } DEBUG(0,("Conversion error: %s(%.80s) %li\n", reason, iptr, (long int)(iptr-src))); talloc_free(dst); return -1; } dstlen = (dstlen-2) - obytes; SSVAL(dst, dstlen, 0); *pdst = dst; return dstlen; } #ifndef HKEY_CURRENT_CONFIG #define HKEY_CURRENT_CONFIG 0x80000005 #endif #ifndef HKEY_DYN_DATA #define HKEY_DYN_DATA 0x80000006 #endif #ifndef HKEY_PERFORMANCE_TEXT #define HKEY_PERFORMANCE_TEXT 0x80000050 #endif #ifndef HKEY_PERFORMANCE_NLSTEXT #define HKEY_PERFORMANCE_NLSTEXT 0x80000060 #endif #define HIVE_INFO_ENTRY(SHORT,LONG) \ const struct hive_info HIVE_INFO_##SHORT = { \ .handle = LONG, \ .short_name = #SHORT, \ .short_name_len = sizeof(#SHORT)-1, \ .long_name = #LONG, \ .long_name_len = sizeof(#LONG)-1, \ } HIVE_INFO_ENTRY(HKLM, HKEY_LOCAL_MACHINE); HIVE_INFO_ENTRY(HKCU, HKEY_CURRENT_USER); HIVE_INFO_ENTRY(HKCR, HKEY_CLASSES_ROOT); HIVE_INFO_ENTRY(HKU , HKEY_USERS); HIVE_INFO_ENTRY(HKCC, HKEY_CURRENT_CONFIG); HIVE_INFO_ENTRY(HKDD, HKEY_DYN_DATA); HIVE_INFO_ENTRY(HKPD, HKEY_PERFORMANCE_DATA); HIVE_INFO_ENTRY(HKPT, HKEY_PERFORMANCE_TEXT); HIVE_INFO_ENTRY(HKPN, HKEY_PERFORMANCE_NLSTEXT); #undef HIVE_INFO_ENTRY const struct hive_info* HIVE_INFO[] = { &HIVE_INFO_HKLM, &HIVE_INFO_HKCU, &HIVE_INFO_HKCR, &HIVE_INFO_HKU, &HIVE_INFO_HKCC, &HIVE_INFO_HKDD, &HIVE_INFO_HKPD, &HIVE_INFO_HKPT, &HIVE_INFO_HKPN, NULL }; #define TOINT(A,B) ((int)(A) << 8) + (int)(B) bool srprs_hive(const char** ptr, const struct hive_info** result) { const char* str = *ptr; const struct hive_info* info = NULL; bool long_hive = false; if ((toupper(str[0]) != 'H') || (toupper(str[1]) != 'K') || (str[2] == '\0') ) { return false; } switch ( TOINT(toupper(str[2]), toupper(str[3])) ) { case TOINT('E', 'Y'): if (str[4] == '_') { int i; for (i=0; (info = HIVE_INFO[i]); i++) { if (strncmp(&str[5], &info->long_name[5], info->long_name_len-5) == 0) { long_hive = true; break; } } } break; case TOINT('L', 'M'): info = &HIVE_INFO_HKLM; break; case TOINT('C', 'U'): info = &HIVE_INFO_HKCU; break; case TOINT('C', 'R'): info = &HIVE_INFO_HKCR; break; case TOINT('C', 'C'): info = &HIVE_INFO_HKCC; break; case TOINT('D', 'D'): info = &HIVE_INFO_HKDD; break; case TOINT('P', 'D'): info = &HIVE_INFO_HKPD; break; case TOINT('P', 'T'): info = &HIVE_INFO_HKPT; break; case TOINT('P', 'N'): info = &HIVE_INFO_HKPN; break; default: if (toupper(str[2]) == 'U') { info = &HIVE_INFO_HKU; } break; } if (info != NULL) { if (result != NULL) { *result = info; } *ptr += long_hive ? info->long_name_len : info->short_name_len; return true; } return false; } const struct hive_info* hive_info(const char* name) { const struct hive_info* info = NULL; srprs_hive(&name, &info); return info; } const char* get_charset(const char* c) { if (strcmp(c, "dos") == 0) { return lp_dos_charset(); } else if (strcmp(c, "unix") == 0) { return lp_unix_charset(); } else { return c; } } bool set_iconv(smb_iconv_t* t, const char* to, const char* from) { smb_iconv_t cd = (smb_iconv_t)-1; if (to && from) { to = get_charset(to); from = get_charset(from); cd = smb_iconv_open(to, from); if (cd == ((smb_iconv_t)-1)) { return false; } } if ((*t != (smb_iconv_t)NULL) && (*t != (smb_iconv_t)-1)) { smb_iconv_close(*t); } *t = cd; return true; } /** * Parse option string * @param[in,out] ptr parse position * @param[in] mem_ctx talloc context * @param[out] name ptr 2 value * @param[out] value ptr 2 value * @return true on success */ bool srprs_option(const char** ptr, const void* mem_ctx, char** name, char** value) { const char* pos = *ptr; void* ctx = talloc_new(mem_ctx); cbuf* key = cbuf_new(ctx); cbuf* val = NULL; while(srprs_charsetinv(&pos, ",= \t\n\r", key)) ; if (pos == *ptr) { talloc_free(ctx); return false; } if (name != NULL) { *name = talloc_steal(mem_ctx, cbuf_gets(key, 0)); } if (*pos == '=') { val = cbuf_new(ctx); pos++; if (!srprs_quoted_string(ptr, val, NULL)) { while(srprs_charsetinv(&pos, ", \t\n\r", val)) ; } if (value != NULL) { *value = talloc_steal(mem_ctx, cbuf_gets(val, 0)); } } else { if (value != NULL) { *value = NULL; } } while(srprs_char(&pos, ',')) ; *ptr = pos; return true; } #define CH_INVALID ((charset_t)-1) static const struct { const char* const name; charset_t ctype; int len; uint8_t seq[4]; } BOM[] = { {"UTF-8", CH_UTF8, 3, {0xEF, 0xBB, 0xBF}}, {"UTF-32LE", CH_INVALID, 4, {0xFF, 0xFE, 0x00, 0x00}}, {"UTF-16LE", CH_UTF16LE, 2, {0xFF, 0xFE}}, {"UTF-16BE", CH_UTF16BE, 2, {0xFE, 0xFF}}, {"UTF-32BE", CH_INVALID, 4, {0x00, 0x00, 0xFE, 0xFF}}, { .name = NULL } }; bool srprs_bom(const char** ptr, const char** name, charset_t* ctype) { int i; for (i=0; BOM[i].name; i++) { if (memcmp(*ptr, BOM[i].seq, BOM[i].len) == 0) { break; } } if (BOM[i].name != NULL) { DEBUG(0, ("Found Byte Order Mark for : %s\n", BOM[i].name)); if (name != NULL) { *name = BOM[i].name; } if (ctype != NULL) { *ctype = BOM[i].ctype; } *ptr += BOM[i].len; return true; } return false; } int write_bom(FILE* file, const char* charset, charset_t ctype) { int i; if ( charset == NULL ) { for (i=0; BOM[i].name; i++) { if (BOM[i].ctype == ctype) { return fwrite(BOM[i].seq, 1, BOM[i].len, file); } } DEBUG(0, ("No Byte Order Mark for charset_t: %u\n", (unsigned)ctype)); } else { for (i=0; BOM[i].name; i++) { if (strcasecmp_m(BOM[i].name, charset) == 0) { return fwrite(BOM[i].seq, 1, BOM[i].len, file); } } DEBUG(0, ("No Byte Order Mark for charset_t: %s\n", charset)); } return 0; } int cbuf_puts_case(cbuf* s, const char* str, size_t len, enum fmt_case fmt) { size_t pos = cbuf_getpos(s); int ret = cbuf_puts(s, str, len); char* ptr = cbuf_gets(s,pos); if (ret <= 0) { return ret; } switch (fmt) { case FMT_CASE_PRESERVE: break; case FMT_CASE_UPPER: while(*ptr != '\0') { *ptr = toupper(*ptr); ptr++; } break; case FMT_CASE_TITLE: *ptr = toupper(*ptr); ptr++; case FMT_CASE_LOWER: while(*ptr != '\0') { *ptr = tolower(*ptr); ptr++; } } return ret; }