| 1 | /*
|
|---|
| 2 | * Samba Unix/Linux SMB client library
|
|---|
| 3 | *
|
|---|
| 4 | * Copyright (C) Gregor Beck 2010
|
|---|
| 5 | *
|
|---|
| 6 | * This program is free software; you can redistribute it and/or modify
|
|---|
| 7 | * it under the terms of the GNU General Public License as published by
|
|---|
| 8 | * the Free Software Foundation; either version 3 of the License, or
|
|---|
| 9 | * (at your option) any later version.
|
|---|
| 10 | *
|
|---|
| 11 | * This program is distributed in the hope that it will be useful,
|
|---|
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|---|
| 14 | * GNU General Public License for more details.
|
|---|
| 15 | *
|
|---|
| 16 | * You should have received a copy of the GNU General Public License
|
|---|
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|---|
| 18 | */
|
|---|
| 19 |
|
|---|
| 20 | /**
|
|---|
| 21 | * @brief Parser for dot.reg files
|
|---|
| 22 | * @file reg_parse.c
|
|---|
| 23 | * @author Gregor Beck <gb@sernet.de>
|
|---|
| 24 | * @date Jun 2010
|
|---|
| 25 | *
|
|---|
| 26 | */
|
|---|
| 27 |
|
|---|
| 28 | #include "includes.h"
|
|---|
| 29 | #include "system/filesys.h"
|
|---|
| 30 | #include "cbuf.h"
|
|---|
| 31 | #include "srprs.h"
|
|---|
| 32 | #include "reg_parse_internal.h"
|
|---|
| 33 | #include "reg_parse.h"
|
|---|
| 34 | #include "reg_format.h"
|
|---|
| 35 |
|
|---|
| 36 | #include <stdio.h>
|
|---|
| 37 | #include <unistd.h>
|
|---|
| 38 | #include <wchar.h>
|
|---|
| 39 | #include <talloc.h>
|
|---|
| 40 | #include <stdbool.h>
|
|---|
| 41 | #include <string.h>
|
|---|
| 42 | #include <sys/types.h>
|
|---|
| 43 | #include <regex.h>
|
|---|
| 44 | #include <assert.h>
|
|---|
| 45 | #include <stdint.h>
|
|---|
| 46 |
|
|---|
| 47 | enum reg_parse_state {
|
|---|
| 48 | STATE_DEFAULT,
|
|---|
| 49 | STATE_KEY_OPEN,
|
|---|
| 50 | STATE_VAL_HEX_CONT,
|
|---|
| 51 | STATE_VAL_SZ_CONT
|
|---|
| 52 | };
|
|---|
| 53 |
|
|---|
| 54 | struct reg_parse {
|
|---|
| 55 | struct reg_format_callback reg_format_callback;
|
|---|
| 56 | cbuf* key;
|
|---|
| 57 | cbuf* valname;
|
|---|
| 58 | uint32_t valtype;
|
|---|
| 59 | cbuf* valblob;
|
|---|
| 60 | cbuf* tmp;
|
|---|
| 61 | struct reg_parse_callback call;
|
|---|
| 62 | int ret;
|
|---|
| 63 | int linenum;
|
|---|
| 64 | enum reg_parse_state state;
|
|---|
| 65 | struct reg_parse_options* opt;
|
|---|
| 66 | smb_iconv_t str2UTF16;
|
|---|
| 67 | unsigned flags;
|
|---|
| 68 | };
|
|---|
| 69 |
|
|---|
| 70 | /**
|
|---|
| 71 | * @defgroup action Action
|
|---|
| 72 | * @{
|
|---|
| 73 | */
|
|---|
| 74 | static bool act_key(struct reg_parse* p, cbuf* keyname, bool del)
|
|---|
| 75 | {
|
|---|
| 76 | const char* name = cbuf_gets(keyname, 0);
|
|---|
| 77 | cbuf_swap(p->key, keyname);
|
|---|
| 78 |
|
|---|
| 79 | assert(p->state == STATE_DEFAULT || p->state == STATE_KEY_OPEN);
|
|---|
| 80 | p->state = del ? STATE_DEFAULT : STATE_KEY_OPEN;
|
|---|
| 81 |
|
|---|
| 82 | assert(p->call.key);
|
|---|
| 83 | p->ret = p->call.key(p->call.data, &name, 1, del);
|
|---|
| 84 | return p->ret >= 0;
|
|---|
| 85 | }
|
|---|
| 86 |
|
|---|
| 87 | static bool value_callback(struct reg_parse* p)
|
|---|
| 88 | {
|
|---|
| 89 | const char* name = cbuf_gets(p->valname,0);
|
|---|
| 90 | const uint8_t* val = (const uint8_t*)cbuf_gets(p->valblob,0);
|
|---|
| 91 | size_t len = cbuf_getpos(p->valblob);
|
|---|
| 92 |
|
|---|
| 93 | assert(p->call.val);
|
|---|
| 94 | p->ret = p->call.val(p->call.data, name, p->valtype, val, len);
|
|---|
| 95 | return p->ret >= 0;
|
|---|
| 96 | }
|
|---|
| 97 |
|
|---|
| 98 | static bool act_val_hex(struct reg_parse* p, cbuf* value, bool cont)
|
|---|
| 99 | {
|
|---|
| 100 | cbuf_swap(p->valblob, value);
|
|---|
| 101 | assert((p->state == STATE_KEY_OPEN) || (p->state == STATE_VAL_HEX_CONT));
|
|---|
| 102 |
|
|---|
| 103 | if (cont) {
|
|---|
| 104 | p->state = STATE_VAL_HEX_CONT;
|
|---|
| 105 | } else {
|
|---|
| 106 | p->state = STATE_KEY_OPEN;
|
|---|
| 107 |
|
|---|
| 108 | switch (p->valtype) {
|
|---|
| 109 | case REG_EXPAND_SZ:
|
|---|
| 110 | case REG_MULTI_SZ:
|
|---|
| 111 | if (p->str2UTF16 != NULL) {
|
|---|
| 112 | char* dst = NULL;
|
|---|
| 113 | const char* src = cbuf_gets(p->valblob, 0);
|
|---|
| 114 | const size_t slen = cbuf_getpos(p->valblob);
|
|---|
| 115 | size_t dlen = iconvert_talloc(p,
|
|---|
| 116 | p->str2UTF16,
|
|---|
| 117 | src, slen,
|
|---|
| 118 | &dst);
|
|---|
| 119 | if (dlen != -1) {
|
|---|
| 120 | cbuf_swapptr(p->valblob, &dst, dlen);
|
|---|
| 121 | } else {
|
|---|
| 122 | DEBUG(0, ("iconvert_talloc failed\n"));
|
|---|
| 123 | }
|
|---|
| 124 | talloc_free(dst);
|
|---|
| 125 | }
|
|---|
| 126 | default:
|
|---|
| 127 | break;
|
|---|
| 128 | }
|
|---|
| 129 | return value_callback(p);
|
|---|
| 130 | }
|
|---|
| 131 | return true;
|
|---|
| 132 | }
|
|---|
| 133 |
|
|---|
| 134 | static bool act_val_dw(struct reg_parse* p, uint32_t val)
|
|---|
| 135 | {
|
|---|
| 136 | assert(p->valtype == REG_DWORD);
|
|---|
| 137 | assert(p->state == STATE_KEY_OPEN);
|
|---|
| 138 |
|
|---|
| 139 | cbuf_clear(p->valblob);
|
|---|
| 140 |
|
|---|
| 141 | if (cbuf_putdw(p->valblob, val) < 0) {
|
|---|
| 142 | return false;
|
|---|
| 143 | }
|
|---|
| 144 | return value_callback(p);
|
|---|
| 145 | }
|
|---|
| 146 |
|
|---|
| 147 | static bool act_val_sz(struct reg_parse* p, cbuf* value, bool cont)
|
|---|
| 148 | {
|
|---|
| 149 | cbuf_swap(p->valblob, value);
|
|---|
| 150 |
|
|---|
| 151 | assert(p->valtype == REG_SZ);
|
|---|
| 152 | assert((p->state == STATE_KEY_OPEN) || (p->state == STATE_VAL_SZ_CONT));
|
|---|
| 153 |
|
|---|
| 154 | if (cont) {
|
|---|
| 155 | p->state = STATE_VAL_SZ_CONT;
|
|---|
| 156 | } else {
|
|---|
| 157 | char* dst = NULL;
|
|---|
| 158 | size_t dlen;
|
|---|
| 159 | const char* src = cbuf_gets(p->valblob, 0);
|
|---|
| 160 |
|
|---|
| 161 | p->state = STATE_KEY_OPEN;
|
|---|
| 162 |
|
|---|
| 163 |
|
|---|
| 164 | if (convert_string_talloc(p->valblob, CH_UNIX, CH_UTF16LE,
|
|---|
| 165 | src, strlen(src)+1,
|
|---|
| 166 | &dst, &dlen, true))
|
|---|
| 167 | {
|
|---|
| 168 | cbuf_swapptr(p->valblob, &dst, dlen);
|
|---|
| 169 | } else {
|
|---|
| 170 | DEBUG(0, ("convert_string_talloc failed: >%s<\n"
|
|---|
| 171 | "use it as is\t", src));
|
|---|
| 172 | }
|
|---|
| 173 | talloc_free(dst);
|
|---|
| 174 |
|
|---|
| 175 | return value_callback(p);
|
|---|
| 176 | }
|
|---|
| 177 | return true;
|
|---|
| 178 | }
|
|---|
| 179 |
|
|---|
| 180 | static bool act_val_del(struct reg_parse* p)
|
|---|
| 181 | {
|
|---|
| 182 | const char* name = cbuf_gets(p->valname, 0);
|
|---|
| 183 |
|
|---|
| 184 | assert(p->call.val_del);
|
|---|
| 185 | p->ret = p->call.val_del(p->call.data, name);
|
|---|
| 186 | return p->ret >= 0;
|
|---|
| 187 | }
|
|---|
| 188 |
|
|---|
| 189 | static bool act_comment (struct reg_parse* p, const char* txt)
|
|---|
| 190 | {
|
|---|
| 191 | assert(p->call.comment);
|
|---|
| 192 | p->ret = p->call.comment(p->call.data, txt);
|
|---|
| 193 | return p->ret >= 0;
|
|---|
| 194 | }
|
|---|
| 195 | /**@}*/
|
|---|
| 196 |
|
|---|
| 197 |
|
|---|
| 198 | static int nop(void* data)
|
|---|
| 199 | {
|
|---|
| 200 | return 0;
|
|---|
| 201 | }
|
|---|
| 202 |
|
|---|
| 203 |
|
|---|
| 204 | struct reg_parse* reg_parse_new(const void* ctx,
|
|---|
| 205 | struct reg_parse_callback cb,
|
|---|
| 206 | const char* str_enc, unsigned flags)
|
|---|
| 207 | {
|
|---|
| 208 | struct reg_parse* s = talloc_zero(ctx, struct reg_parse);
|
|---|
| 209 | if (s == NULL)
|
|---|
| 210 | return NULL;
|
|---|
| 211 | s->key = cbuf_new(s);
|
|---|
| 212 | s->valname = cbuf_new(s);
|
|---|
| 213 | s->valblob = cbuf_new(s);
|
|---|
| 214 | s->tmp = cbuf_new(s);
|
|---|
| 215 | if ( (s->tmp == NULL) || (s->valblob == NULL)
|
|---|
| 216 | || (s->valname == NULL) || (s->key == NULL) )
|
|---|
| 217 | {
|
|---|
| 218 | goto fail;
|
|---|
| 219 | }
|
|---|
| 220 |
|
|---|
| 221 | s->reg_format_callback.writeline = (reg_format_callback_writeline_t)®_parse_line;
|
|---|
| 222 | s->reg_format_callback.data = s;
|
|---|
| 223 |
|
|---|
| 224 | s->valtype = 0;
|
|---|
| 225 | if (cb.key == NULL) {
|
|---|
| 226 | cb.key = (reg_parse_callback_key_t)&nop;
|
|---|
| 227 | }
|
|---|
| 228 | if (cb.val == NULL) {
|
|---|
| 229 | cb.val = (reg_parse_callback_val_t)&nop;
|
|---|
| 230 | }
|
|---|
| 231 | if (cb.val_del == NULL) {
|
|---|
| 232 | cb.val_del = (reg_parse_callback_val_del_t)&nop;
|
|---|
| 233 | }
|
|---|
| 234 | if (cb.comment == NULL) {
|
|---|
| 235 | cb.comment = (reg_parse_callback_comment_t)&nop;
|
|---|
| 236 | }
|
|---|
| 237 |
|
|---|
| 238 | s->call = cb;
|
|---|
| 239 | s->linenum = 0;
|
|---|
| 240 | s->state = STATE_DEFAULT;
|
|---|
| 241 | s->flags = flags;
|
|---|
| 242 |
|
|---|
| 243 | if (str_enc && !set_iconv(&s->str2UTF16, "UTF-16LE", str_enc)) {
|
|---|
| 244 | DEBUG(0, ("reg_parse_new: failed to set encoding: %s",
|
|---|
| 245 | str_enc));
|
|---|
| 246 | goto fail;
|
|---|
| 247 | }
|
|---|
| 248 |
|
|---|
| 249 | assert(&s->reg_format_callback == (struct reg_format_callback*)s);
|
|---|
| 250 | return s;
|
|---|
| 251 | fail:
|
|---|
| 252 | talloc_free(s);
|
|---|
| 253 | return NULL;
|
|---|
| 254 | }
|
|---|
| 255 |
|
|---|
| 256 | /**
|
|---|
| 257 | * @defgroup parse Parser Primitive
|
|---|
| 258 | * @ingroup internal
|
|---|
| 259 | * @{
|
|---|
| 260 | */
|
|---|
| 261 |
|
|---|
| 262 |
|
|---|
| 263 | static bool srprs_key(const char** ptr, cbuf* key, bool* del)
|
|---|
| 264 | {
|
|---|
| 265 | const char* pos = *ptr;
|
|---|
| 266 | const char* closing_bracket_pos = NULL;
|
|---|
| 267 | size_t closing_bracket_idx = 0;
|
|---|
| 268 |
|
|---|
| 269 | if (!srprs_skipws(&pos) || !srprs_char(&pos, '[')) {
|
|---|
| 270 | return false;
|
|---|
| 271 | }
|
|---|
| 272 |
|
|---|
| 273 | *del = srprs_char(&pos, '-');
|
|---|
| 274 |
|
|---|
| 275 | cbuf_clear(key);
|
|---|
| 276 |
|
|---|
| 277 | while (true) {
|
|---|
| 278 | while (srprs_charsetinv(&pos, "]\\", key))
|
|---|
| 279 | ;
|
|---|
| 280 |
|
|---|
| 281 | switch (*pos) {
|
|---|
| 282 |
|
|---|
| 283 | case ']':
|
|---|
| 284 | closing_bracket_idx = cbuf_getpos(key);
|
|---|
| 285 | closing_bracket_pos = pos;
|
|---|
| 286 | cbuf_putc(key, ']');
|
|---|
| 287 | pos++;
|
|---|
| 288 | break;
|
|---|
| 289 |
|
|---|
| 290 | case '\\':
|
|---|
| 291 | cbuf_putc(key, '\\');
|
|---|
| 292 | /* n++; */
|
|---|
| 293 | /* cbuf_puts(subkeyidx, cbuf_getpos(key), sizeof(size_t)) */
|
|---|
| 294 | while (srprs_char(&pos,'\\'))
|
|---|
| 295 | ;
|
|---|
| 296 | break;
|
|---|
| 297 |
|
|---|
| 298 | case '\0':
|
|---|
| 299 | if (closing_bracket_pos == NULL) {
|
|---|
| 300 | return false;
|
|---|
| 301 | }
|
|---|
| 302 |
|
|---|
| 303 | /* remove trailing backslash (if any) */
|
|---|
| 304 | if (*(closing_bracket_pos-1)=='\\') {
|
|---|
| 305 | closing_bracket_idx--;
|
|---|
| 306 | }
|
|---|
| 307 |
|
|---|
| 308 | cbuf_setpos(key, closing_bracket_idx);
|
|---|
| 309 | *ptr = closing_bracket_pos+1;
|
|---|
| 310 | return true;
|
|---|
| 311 |
|
|---|
| 312 | default:
|
|---|
| 313 | assert(false);
|
|---|
| 314 | }
|
|---|
| 315 | }
|
|---|
| 316 | }
|
|---|
| 317 |
|
|---|
| 318 | static bool srprs_val_name(const char** ptr, cbuf* name)
|
|---|
| 319 | {
|
|---|
| 320 | const char* pos = *ptr;
|
|---|
| 321 | const size_t spos = cbuf_getpos(name);
|
|---|
| 322 |
|
|---|
| 323 | if ( !srprs_skipws(&pos) ) {
|
|---|
| 324 | goto fail;
|
|---|
| 325 | }
|
|---|
| 326 |
|
|---|
| 327 | if ( srprs_char(&pos, '@') ) {
|
|---|
| 328 | cbuf_puts(name, "", -1);
|
|---|
| 329 | }
|
|---|
| 330 | else if (!srprs_quoted_string(&pos, name, NULL)) {
|
|---|
| 331 | goto fail;
|
|---|
| 332 | }
|
|---|
| 333 |
|
|---|
| 334 | if (!srprs_skipws(&pos) || !srprs_char(&pos, '=')) {
|
|---|
| 335 | goto fail;
|
|---|
| 336 | }
|
|---|
| 337 |
|
|---|
| 338 | *ptr = pos;
|
|---|
| 339 | return true;
|
|---|
| 340 |
|
|---|
| 341 | fail:
|
|---|
| 342 | cbuf_setpos(name, spos);
|
|---|
| 343 | return false;
|
|---|
| 344 | }
|
|---|
| 345 |
|
|---|
| 346 | static bool srprs_val_dword(const char** ptr, uint32_t* type, uint32_t* val)
|
|---|
| 347 | {
|
|---|
| 348 | const char* pos = *ptr;
|
|---|
| 349 |
|
|---|
| 350 | if (!srprs_str(&pos, "dword:", -1)) {
|
|---|
| 351 | return false;
|
|---|
| 352 | }
|
|---|
| 353 |
|
|---|
| 354 | if (!srprs_hex(&pos, 8, val)) {
|
|---|
| 355 | return false;
|
|---|
| 356 | }
|
|---|
| 357 |
|
|---|
| 358 | *type = REG_DWORD;
|
|---|
| 359 | *ptr = pos;
|
|---|
| 360 | return true;
|
|---|
| 361 | }
|
|---|
| 362 |
|
|---|
| 363 | static bool srprs_val_sz(const char** ptr, uint32_t* type, cbuf* val, bool* cont)
|
|---|
| 364 | {
|
|---|
| 365 | if (!srprs_quoted_string(ptr, val, cont)) {
|
|---|
| 366 | return false;
|
|---|
| 367 | }
|
|---|
| 368 |
|
|---|
| 369 | *type = REG_SZ;
|
|---|
| 370 | return true;
|
|---|
| 371 | }
|
|---|
| 372 |
|
|---|
| 373 |
|
|---|
| 374 | static bool srprs_nl_no_eos(const char** ptr, cbuf* str, bool eof)
|
|---|
| 375 | {
|
|---|
| 376 | const char* pos = *ptr;
|
|---|
| 377 | const size_t spos = cbuf_getpos(str);
|
|---|
| 378 |
|
|---|
| 379 | if( srprs_nl(&pos, str) && (eof || *pos != '\0')) {
|
|---|
| 380 | *ptr = pos;
|
|---|
| 381 | return true;
|
|---|
| 382 | }
|
|---|
| 383 | cbuf_setpos(str, spos);
|
|---|
| 384 | return false;
|
|---|
| 385 | }
|
|---|
| 386 |
|
|---|
| 387 |
|
|---|
| 388 | static bool srprs_eol_cont(const char** ptr, bool* cont)
|
|---|
| 389 | {
|
|---|
| 390 | const char* pos = *ptr;
|
|---|
| 391 | bool bs = srprs_char(&pos, '\\');
|
|---|
| 392 |
|
|---|
| 393 | if (!srprs_eol(&pos, NULL)) {
|
|---|
| 394 | return false;
|
|---|
| 395 | }
|
|---|
| 396 |
|
|---|
| 397 | *cont = bs;
|
|---|
| 398 | *ptr = pos;
|
|---|
| 399 | return true;
|
|---|
| 400 | }
|
|---|
| 401 |
|
|---|
| 402 | /* matches the empty string, for zero length lists */
|
|---|
| 403 | static bool srprs_val_hex_values(const char** ptr, cbuf* val, bool* cont)
|
|---|
| 404 | {
|
|---|
| 405 | const char* pos = *ptr;
|
|---|
| 406 | unsigned u;
|
|---|
| 407 |
|
|---|
| 408 | do {
|
|---|
| 409 | if (!srprs_skipws(&pos) || !srprs_hex(&pos, 2, &u) || !srprs_skipws(&pos)) {
|
|---|
| 410 | break;
|
|---|
| 411 | }
|
|---|
| 412 | cbuf_putc(val, (char)u);
|
|---|
| 413 | } while(srprs_char(&pos, ','));
|
|---|
| 414 |
|
|---|
| 415 | *ptr = pos;
|
|---|
| 416 |
|
|---|
| 417 | if (srprs_skipws(&pos) && srprs_eol_cont(&pos, cont)) {
|
|---|
| 418 | *ptr = pos;
|
|---|
| 419 | }
|
|---|
| 420 |
|
|---|
| 421 | return true;
|
|---|
| 422 | }
|
|---|
| 423 |
|
|---|
| 424 | static bool srprs_val_hex(const char** ptr, uint32_t* ptype, cbuf* val,
|
|---|
| 425 | bool* cont)
|
|---|
| 426 | {
|
|---|
| 427 | const char* pos = *ptr;
|
|---|
| 428 | uint32_t type;
|
|---|
| 429 |
|
|---|
| 430 | if (!srprs_str(&pos, "hex", -1)) {
|
|---|
| 431 | return false;
|
|---|
| 432 | }
|
|---|
| 433 |
|
|---|
| 434 | if (srprs_char(&pos, ':')) {
|
|---|
| 435 | type = REG_BINARY;
|
|---|
| 436 | }
|
|---|
| 437 | else if (!srprs_char(&pos, '(') ||
|
|---|
| 438 | !srprs_hex(&pos, 8, &type) ||
|
|---|
| 439 | !srprs_char(&pos,')') ||
|
|---|
| 440 | !srprs_char(&pos, ':'))
|
|---|
| 441 | {
|
|---|
| 442 | return false;
|
|---|
| 443 | }
|
|---|
| 444 |
|
|---|
| 445 | if (!srprs_val_hex_values(&pos, val, cont)) {
|
|---|
| 446 | return false;
|
|---|
| 447 | }
|
|---|
| 448 |
|
|---|
| 449 | *ptype = type;
|
|---|
| 450 | *ptr = pos;
|
|---|
| 451 | return true;
|
|---|
| 452 | }
|
|---|
| 453 |
|
|---|
| 454 |
|
|---|
| 455 | static bool srprs_comment(const char** ptr, cbuf* str)
|
|---|
| 456 | {
|
|---|
| 457 | return srprs_char(ptr, ';') && srprs_line(ptr, str);
|
|---|
| 458 | }
|
|---|
| 459 |
|
|---|
| 460 | /**@}*/
|
|---|
| 461 |
|
|---|
| 462 | int reg_parse_set_options(struct reg_parse* parser, const char* options)
|
|---|
| 463 | {
|
|---|
| 464 | static const char* DEFAULT ="enc=unix,flags=0";
|
|---|
| 465 |
|
|---|
| 466 | int ret = 0;
|
|---|
| 467 | char *key, *val;
|
|---|
| 468 | void* ctx = talloc_new(parser);
|
|---|
| 469 |
|
|---|
| 470 | if (options == NULL) {
|
|---|
| 471 | options = DEFAULT;
|
|---|
| 472 | }
|
|---|
| 473 |
|
|---|
| 474 | while (srprs_option(&options, ctx, &key, &val)) {
|
|---|
| 475 | if ((strcmp(key, "enc") == 0) || (strcmp(key, "strenc") == 0)) {
|
|---|
| 476 | } else if ((strcmp(key, "flags") == 0) && (val != NULL)) {
|
|---|
| 477 | char* end = NULL;
|
|---|
| 478 | if (val != NULL) {
|
|---|
| 479 | parser->flags = strtol(val, &end, 0);
|
|---|
| 480 | }
|
|---|
| 481 | if ((end==NULL) || (*end != '\0')) {
|
|---|
| 482 | DEBUG(0, ("Invalid flags format: %s\n",
|
|---|
| 483 | val ? val : "<NULL>"));
|
|---|
| 484 | ret = -1;
|
|---|
| 485 | }
|
|---|
| 486 | }
|
|---|
| 487 | /* else if (strcmp(key, "hive") == 0) { */
|
|---|
| 488 | /* if (strcmp(val, "short") == 0) { */
|
|---|
| 489 | /* f->hive_fmt = REG_FMT_SHORT_HIVES; */
|
|---|
| 490 | /* } else if (strcmp(val, "long") == 0) { */
|
|---|
| 491 | /* f->hive_fmt = REG_FMT_LONG_HIVES; */
|
|---|
| 492 | /* } else if (strcmp(val, "preserve") == 0) { */
|
|---|
| 493 | /* f->hive_fmt = REG_FMT_PRESERVE_HIVES; */
|
|---|
| 494 | /* } else { */
|
|---|
| 495 | /* DEBUG(0, ("Invalid hive format: %s\n", val)); */
|
|---|
| 496 | /* ret = -1; */
|
|---|
| 497 | /* } */
|
|---|
| 498 | /* } */
|
|---|
| 499 | }
|
|---|
| 500 | talloc_free(ctx);
|
|---|
| 501 | return ret;
|
|---|
| 502 | }
|
|---|
| 503 |
|
|---|
| 504 |
|
|---|
| 505 | int reg_parse_line(struct reg_parse* parser, const char* line)
|
|---|
| 506 | {
|
|---|
| 507 | const char* pos;
|
|---|
| 508 | bool del=false;
|
|---|
| 509 | cbuf* tmp=cbuf_clear(parser->tmp);
|
|---|
| 510 | bool cb_ok = true;
|
|---|
| 511 | bool cont = true;
|
|---|
| 512 |
|
|---|
| 513 | if (!line) {
|
|---|
| 514 | return -4;
|
|---|
| 515 | }
|
|---|
| 516 |
|
|---|
| 517 | parser->linenum++;
|
|---|
| 518 | pos = line;
|
|---|
| 519 |
|
|---|
| 520 | switch (parser->state) {
|
|---|
| 521 | case STATE_VAL_HEX_CONT:
|
|---|
| 522 | if (srprs_val_hex_values(&pos, parser->valblob, &cont)) {
|
|---|
| 523 | cb_ok = act_val_hex(parser, parser->valblob, cont);
|
|---|
| 524 | }
|
|---|
| 525 | goto done;
|
|---|
| 526 | case STATE_VAL_SZ_CONT:
|
|---|
| 527 | if (srprs_quoted_string(&pos, parser->valblob, &cont)) {
|
|---|
| 528 | cb_ok = act_val_sz(parser, parser->valblob, cont);
|
|---|
| 529 | }
|
|---|
| 530 | goto done;
|
|---|
| 531 | default:
|
|---|
| 532 | cont = false;
|
|---|
| 533 | }
|
|---|
| 534 |
|
|---|
| 535 | if ( !srprs_skipws(&pos) ) {
|
|---|
| 536 | return -4;
|
|---|
| 537 | }
|
|---|
| 538 |
|
|---|
| 539 | /* empty line ?*/
|
|---|
| 540 | if ( srprs_eol(&pos, NULL) ) {
|
|---|
| 541 | return 0;
|
|---|
| 542 | }
|
|---|
| 543 |
|
|---|
| 544 | /* key line ?*/
|
|---|
| 545 | else if (srprs_key(&pos, tmp, &del)) {
|
|---|
| 546 | cb_ok = act_key(parser, tmp, del);
|
|---|
| 547 | }
|
|---|
| 548 |
|
|---|
| 549 | /* comment line ? */
|
|---|
| 550 | else if (srprs_comment(&pos, tmp)) {
|
|---|
| 551 | cb_ok = act_comment(parser, cbuf_gets(tmp, 0));
|
|---|
| 552 | }
|
|---|
| 553 |
|
|---|
| 554 | /* head line */
|
|---|
| 555 | else if ((parser->linenum == 1) && srprs_line(&pos, tmp) ) {
|
|---|
| 556 | /* cb_ok = act_head(parser, cbuf_gets(tmp, 0)); */
|
|---|
| 557 | }
|
|---|
| 558 |
|
|---|
| 559 | /* value line ?*/
|
|---|
| 560 | else if (srprs_val_name(&pos, tmp)) {
|
|---|
| 561 | uint32_t dw;
|
|---|
| 562 | cbuf_swap(parser->valname, tmp);
|
|---|
| 563 | cbuf_clear(tmp);
|
|---|
| 564 |
|
|---|
| 565 | if (parser->state != STATE_KEY_OPEN) {
|
|---|
| 566 | DEBUG(0, ("value \"%s\" without a key at line: %i",
|
|---|
| 567 | cbuf_gets(parser->valname, 0), parser->linenum));
|
|---|
| 568 | return -3;
|
|---|
| 569 | }
|
|---|
| 570 |
|
|---|
| 571 | if (!srprs_skipws(&pos)) {
|
|---|
| 572 | return -4;
|
|---|
| 573 | }
|
|---|
| 574 |
|
|---|
| 575 | if (srprs_char(&pos, '-')) {
|
|---|
| 576 | cb_ok = act_val_del(parser);
|
|---|
| 577 | }
|
|---|
| 578 | else if (srprs_val_dword(&pos, &parser->valtype, &dw)) {
|
|---|
| 579 | cb_ok = act_val_dw(parser, dw);
|
|---|
| 580 | }
|
|---|
| 581 | else if (srprs_val_sz(&pos, &parser->valtype, tmp, &cont)) {
|
|---|
| 582 | cb_ok = act_val_sz(parser, tmp, cont);
|
|---|
| 583 | }
|
|---|
| 584 | else if (srprs_val_hex(&pos, &parser->valtype, tmp, &cont)){
|
|---|
| 585 | cb_ok = act_val_hex(parser, tmp, cont);
|
|---|
| 586 | }
|
|---|
| 587 | else {
|
|---|
| 588 | DEBUG(0, ("value \"%s\" parse error"
|
|---|
| 589 | "at line: %i pos: %li : %s",
|
|---|
| 590 | cbuf_gets(parser->valname, 0), parser->linenum,
|
|---|
| 591 | (long int)(pos-line), pos));
|
|---|
| 592 | return -3;
|
|---|
| 593 | }
|
|---|
| 594 | }
|
|---|
| 595 | else {
|
|---|
| 596 | DEBUG(0, ("unrecognized line %i : %s\n", parser->linenum, line));
|
|---|
| 597 | return -3;
|
|---|
| 598 | }
|
|---|
| 599 |
|
|---|
| 600 | done:
|
|---|
| 601 | if (!cb_ok)
|
|---|
| 602 | return -2;
|
|---|
| 603 |
|
|---|
| 604 | if (!srprs_skipws(&pos) || !srprs_eol(&pos, NULL)) {
|
|---|
| 605 | DEBUG(0, ("trailing garbage at line: %i pos: %li : %s\n",
|
|---|
| 606 | parser->linenum, (long int)(pos-line), pos));
|
|---|
| 607 | return -1;
|
|---|
| 608 | }
|
|---|
| 609 | return 0;
|
|---|
| 610 | }
|
|---|
| 611 |
|
|---|
| 612 | /******************************************************************************/
|
|---|
| 613 | /**
|
|---|
| 614 | * @addtogroup misc
|
|---|
| 615 | * @{
|
|---|
| 616 | */
|
|---|
| 617 | static bool lookslike_utf16(const char* line, size_t len, bool* little_endian)
|
|---|
| 618 | {
|
|---|
| 619 | static const uint16_t M_LE = 0xFF80;
|
|---|
| 620 | static const uint16_t M_BE = 0x80FF;
|
|---|
| 621 | uint16_t mask;
|
|---|
| 622 | bool le;
|
|---|
| 623 |
|
|---|
| 624 | size_t l = MIN(len/2, 64);
|
|---|
| 625 | uint16_t* u = (uint16_t*)line;
|
|---|
| 626 | int i;
|
|---|
| 627 |
|
|---|
| 628 | assert(len >= 2);
|
|---|
| 629 |
|
|---|
| 630 | if ( u[0] & M_LE ) {
|
|---|
| 631 | le = true;
|
|---|
| 632 | mask = M_LE;
|
|---|
| 633 | } else if ( u[0] & M_BE ) {
|
|---|
| 634 | le = false;
|
|---|
| 635 | mask = M_BE;
|
|---|
| 636 | } else {
|
|---|
| 637 | return false;
|
|---|
| 638 | }
|
|---|
| 639 |
|
|---|
| 640 | for (i=1; i<l; i++) {
|
|---|
| 641 | if ( u[i] & mask ) {
|
|---|
| 642 | return false;
|
|---|
| 643 | }
|
|---|
| 644 | }
|
|---|
| 645 |
|
|---|
| 646 | *little_endian = le;
|
|---|
| 647 | return true;
|
|---|
| 648 | }
|
|---|
| 649 |
|
|---|
| 650 | static bool lookslike_dos(const char* line, size_t len)
|
|---|
| 651 | {
|
|---|
| 652 | int i;
|
|---|
| 653 | for (i=0; i<len; i++) {
|
|---|
| 654 | if ( (line[i] == '\0') || (line[i] & 0x80) ) {
|
|---|
| 655 | return false;
|
|---|
| 656 | }
|
|---|
| 657 | if ( (line[i] == '\r') && (i+1 < len) && (line[i+1] == '\n') ) {
|
|---|
| 658 | return true;
|
|---|
| 659 | }
|
|---|
| 660 | }
|
|---|
| 661 | return false;
|
|---|
| 662 | }
|
|---|
| 663 |
|
|---|
| 664 | static bool guess_charset(const char** ptr,
|
|---|
| 665 | size_t* len,
|
|---|
| 666 | const char** file_enc,
|
|---|
| 667 | const char** str_enc)
|
|---|
| 668 | {
|
|---|
| 669 | const char* charset = NULL;
|
|---|
| 670 | const char* pos = *ptr;
|
|---|
| 671 |
|
|---|
| 672 | if (*len < 4) {
|
|---|
| 673 | return false;
|
|---|
| 674 | }
|
|---|
| 675 |
|
|---|
| 676 | if (srprs_bom(&pos, &charset, NULL)) {
|
|---|
| 677 | *len -= (pos - *ptr);
|
|---|
| 678 | *ptr = pos;
|
|---|
| 679 | if (*file_enc == NULL) {
|
|---|
| 680 | *file_enc = charset;
|
|---|
| 681 | }
|
|---|
| 682 | else if( strcmp(*file_enc, charset) != 0 ) {
|
|---|
| 683 | DEBUG(0, ("file encoding forced to %s\n",
|
|---|
| 684 | *file_enc));
|
|---|
| 685 | }
|
|---|
| 686 | }
|
|---|
| 687 | else if (*file_enc == NULL) {
|
|---|
| 688 | bool le;
|
|---|
| 689 | if (lookslike_utf16(*ptr, *len, &le)) {
|
|---|
| 690 | *file_enc = le ? "UTF-16LE" : "UTF-16BE";
|
|---|
| 691 | }
|
|---|
| 692 | else if (lookslike_dos(*ptr, *len)) {
|
|---|
| 693 | *file_enc = "dos";
|
|---|
| 694 | }
|
|---|
| 695 | else {
|
|---|
| 696 | *file_enc = "unix";
|
|---|
| 697 | }
|
|---|
| 698 | }
|
|---|
| 699 |
|
|---|
| 700 | if ((str_enc != NULL) && (*str_enc == NULL)) {
|
|---|
| 701 | *str_enc = ( strncmp(*ptr, "REGEDIT4", 8) == 0)
|
|---|
| 702 | ? *file_enc
|
|---|
| 703 | : "UTF-16LE";
|
|---|
| 704 | }
|
|---|
| 705 |
|
|---|
| 706 | return true;
|
|---|
| 707 | }
|
|---|
| 708 | /**@}*/
|
|---|
| 709 |
|
|---|
| 710 | struct reg_parse_fd_opt {
|
|---|
| 711 | const char* file_enc;
|
|---|
| 712 | const char* str_enc;
|
|---|
| 713 | unsigned flags;
|
|---|
| 714 | int fail_level;
|
|---|
| 715 | };
|
|---|
| 716 |
|
|---|
| 717 | static struct reg_parse_fd_opt
|
|---|
| 718 | reg_parse_fd_opt(void* mem_ctx, const char* options)
|
|---|
| 719 | {
|
|---|
| 720 | struct reg_parse_fd_opt ret = {
|
|---|
| 721 | .file_enc = NULL,
|
|---|
| 722 | .str_enc = NULL,
|
|---|
| 723 | .flags = 0,
|
|---|
| 724 | };
|
|---|
| 725 |
|
|---|
| 726 | void* ctx = talloc_new(mem_ctx);
|
|---|
| 727 | char *key, *val;
|
|---|
| 728 |
|
|---|
| 729 | if (options == NULL) {
|
|---|
| 730 | goto done;
|
|---|
| 731 | }
|
|---|
| 732 |
|
|---|
| 733 | while (srprs_option(&options, ctx, &key, &val)) {
|
|---|
| 734 | if (strcmp(key, "enc") == 0) {
|
|---|
| 735 | ret.file_enc = talloc_steal(mem_ctx, val);
|
|---|
| 736 | ret.str_enc = ret.file_enc;
|
|---|
| 737 | } else if (strcmp(key, "strenc") == 0) {
|
|---|
| 738 | ret.str_enc = talloc_steal(mem_ctx, val);
|
|---|
| 739 | } else if (strcmp(key, "fileenc") == 0) {
|
|---|
| 740 | ret.file_enc = talloc_steal(mem_ctx, val);
|
|---|
| 741 | } else if ((strcmp(key, "flags") == 0) && (val != NULL)) {
|
|---|
| 742 | char* end = NULL;
|
|---|
| 743 | if (val != NULL) {
|
|---|
| 744 | ret.flags = strtol(val, &end, 0);
|
|---|
| 745 | }
|
|---|
| 746 | if ((end==NULL) || (*end != '\0')) {
|
|---|
| 747 | DEBUG(0, ("Invalid format \"%s\": %s\n",
|
|---|
| 748 | key, val ? val : "<NULL>"));
|
|---|
| 749 | }
|
|---|
| 750 | } else if ((strcmp(key, "fail") == 0) && (val != NULL)) {
|
|---|
| 751 | char* end = NULL;
|
|---|
| 752 | if (val != NULL) {
|
|---|
| 753 | ret.fail_level = -strtol(val, &end, 0);
|
|---|
| 754 | }
|
|---|
| 755 | if ((end==NULL) || (*end != '\0')) {
|
|---|
| 756 | DEBUG(0, ("Invalid format \"%s\": %s\n",
|
|---|
| 757 | key, val ? val : "<NULL>"));
|
|---|
| 758 | }
|
|---|
| 759 | }
|
|---|
| 760 | }
|
|---|
| 761 | done:
|
|---|
| 762 | talloc_free(ctx);
|
|---|
| 763 | return ret;
|
|---|
| 764 | }
|
|---|
| 765 |
|
|---|
| 766 |
|
|---|
| 767 | static void
|
|---|
| 768 | handle_iconv_errno(int err, const char* obuf, size_t linenum,
|
|---|
| 769 | smb_iconv_t cd, const char** iptr, size_t* ilen,
|
|---|
| 770 | char** optr, size_t *olen)
|
|---|
| 771 | {
|
|---|
| 772 | const char *pos = obuf;
|
|---|
| 773 | const char *ptr = obuf;
|
|---|
| 774 | switch(err) {
|
|---|
| 775 | case EINVAL:
|
|---|
| 776 | /* DEBUG(0, ("Incomplete multibyte sequence\n")); */
|
|---|
| 777 | case E2BIG:
|
|---|
| 778 | return;
|
|---|
| 779 | case EILSEQ:
|
|---|
| 780 | break;
|
|---|
| 781 | default:
|
|---|
| 782 | assert(false);
|
|---|
| 783 | }
|
|---|
| 784 |
|
|---|
| 785 | **optr = '\0';
|
|---|
| 786 | while (srprs_line(&ptr, NULL) && srprs_nl(&ptr, NULL)) {
|
|---|
| 787 | pos = ptr;
|
|---|
| 788 | linenum++;
|
|---|
| 789 | }
|
|---|
| 790 | if (pos == *optr) {
|
|---|
| 791 | pos = MAX(obuf, *optr-60);
|
|---|
| 792 | }
|
|---|
| 793 | DEBUG(0, ("Illegal multibyte sequence at line %lu: %s",
|
|---|
| 794 | (long unsigned)(linenum+1), pos));
|
|---|
| 795 |
|
|---|
| 796 | assert((*ilen) > 0);
|
|---|
| 797 | do {
|
|---|
| 798 | size_t il = 1;
|
|---|
| 799 | DEBUGADD(0, ("<%02x>", (unsigned char)**iptr));
|
|---|
| 800 |
|
|---|
| 801 | if ((*olen) > 0) {
|
|---|
| 802 | *(*optr)++ = '\?';
|
|---|
| 803 | (*iptr)++;
|
|---|
| 804 | /* Todo: parametrize, e.g. skip: *optr++ = *iptr++; */
|
|---|
| 805 | (*ilen)--;
|
|---|
| 806 | }
|
|---|
| 807 |
|
|---|
| 808 | if (smb_iconv(cd, iptr, &il, optr, olen) != (size_t)-1 || (errno != EILSEQ)) {
|
|---|
| 809 | if(il == 0)
|
|---|
| 810 | (*ilen)-- ;
|
|---|
| 811 | break;
|
|---|
| 812 | }
|
|---|
| 813 |
|
|---|
| 814 | }
|
|---|
| 815 | while ((*ilen > 0) && (*olen > 0));
|
|---|
| 816 |
|
|---|
| 817 | DEBUGADD(0, ("\n"));
|
|---|
| 818 |
|
|---|
| 819 | }
|
|---|
| 820 |
|
|---|
| 821 | int reg_parse_fd(int fd, const struct reg_parse_callback* cb, const char* opts)
|
|---|
| 822 | {
|
|---|
| 823 | void* mem_ctx = talloc_stackframe();
|
|---|
| 824 | cbuf* line = cbuf_new(mem_ctx);
|
|---|
| 825 | smb_iconv_t cd = (smb_iconv_t)-1;
|
|---|
| 826 | struct reg_parse* parser = NULL;
|
|---|
| 827 | char buf_raw[1024];
|
|---|
| 828 | char buf_unix[1025];
|
|---|
| 829 |
|
|---|
| 830 | ssize_t nread;
|
|---|
| 831 | size_t nconv;
|
|---|
| 832 | const char* pos;
|
|---|
| 833 | const char* iptr;
|
|---|
| 834 | char* optr;
|
|---|
| 835 | size_t ilen;
|
|---|
| 836 | size_t olen;
|
|---|
| 837 | int ret = -1;
|
|---|
| 838 | bool eof = false;
|
|---|
| 839 | size_t linenum = 0;
|
|---|
| 840 |
|
|---|
| 841 | struct reg_parse_fd_opt opt = reg_parse_fd_opt(mem_ctx, opts);
|
|---|
| 842 |
|
|---|
| 843 | if (cb == NULL) {
|
|---|
| 844 | DEBUG(0,("reg_parse_fd: NULL callback\n"));
|
|---|
| 845 | goto done;
|
|---|
| 846 | }
|
|---|
| 847 |
|
|---|
| 848 | nread = read(fd, buf_raw, sizeof(buf_raw));
|
|---|
| 849 | if (nread < 0) {
|
|---|
| 850 | DEBUG(0, ("reg_parse_fd: read failed: %s\n", strerror(errno)));
|
|---|
| 851 | ret = nread;
|
|---|
| 852 | goto done;
|
|---|
| 853 | }
|
|---|
| 854 |
|
|---|
| 855 | iptr = &buf_raw[0];
|
|---|
| 856 | ilen = nread;
|
|---|
| 857 |
|
|---|
| 858 | if (!guess_charset(&iptr, &ilen,
|
|---|
| 859 | &opt.file_enc, &opt.str_enc))
|
|---|
| 860 | {
|
|---|
| 861 | DEBUG(0, ("reg_parse_fd: failed to guess encoding\n"));
|
|---|
| 862 | goto done;
|
|---|
| 863 | }
|
|---|
| 864 |
|
|---|
| 865 | DEBUG(10, ("reg_parse_fd: encoding file: %s str: %s\n",
|
|---|
| 866 | opt.file_enc, opt.str_enc));
|
|---|
| 867 |
|
|---|
| 868 |
|
|---|
| 869 | if (!set_iconv(&cd, "unix", opt.file_enc)) {
|
|---|
| 870 | DEBUG(0, ("reg_parse_fd: failed to set file encoding %s\n",
|
|---|
| 871 | opt.file_enc));
|
|---|
| 872 | goto done;
|
|---|
| 873 | }
|
|---|
| 874 |
|
|---|
| 875 | parser = reg_parse_new(mem_ctx, *cb, opt.str_enc, opt.flags);
|
|---|
| 876 |
|
|---|
| 877 | optr = &buf_unix[0];
|
|---|
| 878 | while (!eof) {
|
|---|
| 879 | olen = sizeof(buf_unix) - (optr - buf_unix) - 1 ;
|
|---|
| 880 | while ( olen > 0 ) {
|
|---|
| 881 | memmove(buf_raw, iptr, ilen);
|
|---|
| 882 |
|
|---|
| 883 | nread = read(fd, buf_raw + ilen, sizeof(buf_raw) - ilen);
|
|---|
| 884 | if (nread < 0) {
|
|---|
| 885 | DEBUG(0, ("reg_parse_fd: read failed: %s\n", strerror(errno)));
|
|---|
| 886 | ret = nread;
|
|---|
| 887 | goto done;
|
|---|
| 888 | }
|
|---|
| 889 |
|
|---|
| 890 | iptr = buf_raw;
|
|---|
| 891 | ilen += nread;
|
|---|
| 892 |
|
|---|
| 893 | if (ilen == 0) {
|
|---|
| 894 | smb_iconv(cd, NULL, NULL, &optr, &olen);
|
|---|
| 895 | eof = true;
|
|---|
| 896 | break;
|
|---|
| 897 | }
|
|---|
| 898 |
|
|---|
| 899 | nconv = smb_iconv(cd, &iptr, &ilen, &optr, &olen);
|
|---|
| 900 |
|
|---|
| 901 | if (nconv == (size_t)-1) {
|
|---|
| 902 | handle_iconv_errno(errno, buf_unix, linenum,
|
|---|
| 903 | cd, &iptr, &ilen,
|
|---|
| 904 | &optr, &olen);
|
|---|
| 905 | break;
|
|---|
| 906 | }
|
|---|
| 907 | }
|
|---|
| 908 | /* process_lines: */
|
|---|
| 909 | *optr = '\0';
|
|---|
| 910 | pos = &buf_unix[0];
|
|---|
| 911 |
|
|---|
| 912 | while ( srprs_line(&pos, line) && srprs_nl_no_eos(&pos, line, eof)) {
|
|---|
| 913 | linenum ++;
|
|---|
| 914 | ret = reg_parse_line(parser, cbuf_gets(line, 0));
|
|---|
| 915 | if (ret < opt.fail_level) {
|
|---|
| 916 | goto done;
|
|---|
| 917 | }
|
|---|
| 918 | cbuf_clear(line);
|
|---|
| 919 | }
|
|---|
| 920 | memmove(buf_unix, pos, optr - pos);
|
|---|
| 921 | optr -= (pos - buf_unix);
|
|---|
| 922 | }
|
|---|
| 923 |
|
|---|
| 924 | ret = 0;
|
|---|
| 925 | done:
|
|---|
| 926 | set_iconv(&cd, NULL, NULL);
|
|---|
| 927 | talloc_free(mem_ctx);
|
|---|
| 928 | return ret;
|
|---|
| 929 | }
|
|---|
| 930 |
|
|---|
| 931 | int reg_parse_file(const char* fname, const struct reg_parse_callback* cb,
|
|---|
| 932 | const char* opt)
|
|---|
| 933 | {
|
|---|
| 934 | int ret = -1;
|
|---|
| 935 | int fd;
|
|---|
| 936 |
|
|---|
| 937 | fd = open(fname, O_RDONLY);
|
|---|
| 938 | if (fd < 0) {
|
|---|
| 939 | DEBUG(0, ("reg_parse_file: open failed: %s\n", strerror(errno)));
|
|---|
| 940 | return -1;
|
|---|
| 941 | }
|
|---|
| 942 |
|
|---|
| 943 | ret = reg_parse_fd(fd, cb, opt);
|
|---|
| 944 |
|
|---|
| 945 | close(fd);
|
|---|
| 946 | return ret;
|
|---|
| 947 | }
|
|---|
| 948 |
|
|---|
| 949 | /* static struct registry_key *find_regkey_by_hnd(pipes_struct *p, */
|
|---|
| 950 | /* struct policy_handle *hnd) */
|
|---|
| 951 | /* { */
|
|---|
| 952 | /* struct registry_key *regkey = NULL; */
|
|---|
| 953 |
|
|---|
| 954 | /* if(!find_policy_by_hnd(p,hnd,(void **)(void *)®key)) { */
|
|---|
| 955 | /* DEBUG(2,("find_regkey_index_by_hnd: Registry Key not found: ")); */
|
|---|
| 956 | /* return NULL; */
|
|---|
| 957 | /* } */
|
|---|
| 958 |
|
|---|
| 959 | /* return regkey; */
|
|---|
| 960 | /* } */
|
|---|