Home | History | Annotate | Download | only in conf
      1 /* crypto/conf/conf.c */
      2 /* Copyright (C) 1995-1998 Eric Young (eay (at) cryptsoft.com)
      3  * All rights reserved.
      4  *
      5  * This package is an SSL implementation written
      6  * by Eric Young (eay (at) cryptsoft.com).
      7  * The implementation was written so as to conform with Netscapes SSL.
      8  *
      9  * This library is free for commercial and non-commercial use as long as
     10  * the following conditions are aheared to.  The following conditions
     11  * apply to all code found in this distribution, be it the RC4, RSA,
     12  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
     13  * included with this distribution is covered by the same copyright terms
     14  * except that the holder is Tim Hudson (tjh (at) cryptsoft.com).
     15  *
     16  * Copyright remains Eric Young's, and as such any Copyright notices in
     17  * the code are not to be removed.
     18  * If this package is used in a product, Eric Young should be given attribution
     19  * as the author of the parts of the library used.
     20  * This can be in the form of a textual message at program startup or
     21  * in documentation (online or textual) provided with the package.
     22  *
     23  * Redistribution and use in source and binary forms, with or without
     24  * modification, are permitted provided that the following conditions
     25  * are met:
     26  * 1. Redistributions of source code must retain the copyright
     27  *    notice, this list of conditions and the following disclaimer.
     28  * 2. Redistributions in binary form must reproduce the above copyright
     29  *    notice, this list of conditions and the following disclaimer in the
     30  *    documentation and/or other materials provided with the distribution.
     31  * 3. All advertising materials mentioning features or use of this software
     32  *    must display the following acknowledgement:
     33  *    "This product includes cryptographic software written by
     34  *     Eric Young (eay (at) cryptsoft.com)"
     35  *    The word 'cryptographic' can be left out if the rouines from the library
     36  *    being used are not cryptographic related :-).
     37  * 4. If you include any Windows specific code (or a derivative thereof) from
     38  *    the apps directory (application code) you must include an acknowledgement:
     39  *    "This product includes software written by Tim Hudson (tjh (at) cryptsoft.com)"
     40  *
     41  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
     42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     51  * SUCH DAMAGE.
     52  *
     53  * The licence and distribution terms for any publically available version or
     54  * derivative of this code cannot be changed.  i.e. this code cannot simply be
     55  * copied and put under another distribution licence
     56  * [including the GNU Public Licence.]
     57  */
     58 
     59 /* Part of the code in here was originally in conf.c, which is now removed */
     60 
     61 #include <stdio.h>
     62 #include <string.h>
     63 #include "cryptlib.h"
     64 #include <openssl/stack.h>
     65 #include <openssl/lhash.h>
     66 #include <openssl/conf.h>
     67 #include <openssl/conf_api.h>
     68 #include "conf_def.h"
     69 #include <openssl/buffer.h>
     70 #include <openssl/err.h>
     71 
     72 static char *eat_ws(CONF *conf, char *p);
     73 static char *eat_alpha_numeric(CONF *conf, char *p);
     74 static void clear_comments(CONF *conf, char *p);
     75 static int str_copy(CONF *conf,char *section,char **to, char *from);
     76 static char *scan_quote(CONF *conf, char *p);
     77 static char *scan_dquote(CONF *conf, char *p);
     78 #define scan_esc(conf,p)	(((IS_EOF((conf),(p)[1]))?((p)+1):((p)+2)))
     79 
     80 static CONF *def_create(CONF_METHOD *meth);
     81 static int def_init_default(CONF *conf);
     82 static int def_init_WIN32(CONF *conf);
     83 static int def_destroy(CONF *conf);
     84 static int def_destroy_data(CONF *conf);
     85 static int def_load(CONF *conf, const char *name, long *eline);
     86 static int def_load_bio(CONF *conf, BIO *bp, long *eline);
     87 static int def_dump(const CONF *conf, BIO *bp);
     88 static int def_is_number(const CONF *conf, char c);
     89 static int def_to_int(const CONF *conf, char c);
     90 
     91 const char CONF_def_version[]="CONF_def" OPENSSL_VERSION_PTEXT;
     92 
     93 static CONF_METHOD default_method = {
     94 	"OpenSSL default",
     95 	def_create,
     96 	def_init_default,
     97 	def_destroy,
     98 	def_destroy_data,
     99 	def_load_bio,
    100 	def_dump,
    101 	def_is_number,
    102 	def_to_int,
    103 	def_load
    104 	};
    105 
    106 static CONF_METHOD WIN32_method = {
    107 	"WIN32",
    108 	def_create,
    109 	def_init_WIN32,
    110 	def_destroy,
    111 	def_destroy_data,
    112 	def_load_bio,
    113 	def_dump,
    114 	def_is_number,
    115 	def_to_int,
    116 	def_load
    117 	};
    118 
    119 CONF_METHOD *NCONF_default()
    120 	{
    121 	return &default_method;
    122 	}
    123 CONF_METHOD *NCONF_WIN32()
    124 	{
    125 	return &WIN32_method;
    126 	}
    127 
    128 static CONF *def_create(CONF_METHOD *meth)
    129 	{
    130 	CONF *ret;
    131 
    132 	ret = OPENSSL_malloc(sizeof(CONF) + sizeof(unsigned short *));
    133 	if (ret)
    134 		if (meth->init(ret) == 0)
    135 			{
    136 			OPENSSL_free(ret);
    137 			ret = NULL;
    138 			}
    139 	return ret;
    140 	}
    141 
    142 static int def_init_default(CONF *conf)
    143 	{
    144 	if (conf == NULL)
    145 		return 0;
    146 
    147 	conf->meth = &default_method;
    148 	conf->meth_data = CONF_type_default;
    149 	conf->data = NULL;
    150 
    151 	return 1;
    152 	}
    153 
    154 static int def_init_WIN32(CONF *conf)
    155 	{
    156 	if (conf == NULL)
    157 		return 0;
    158 
    159 	conf->meth = &WIN32_method;
    160 	conf->meth_data = (void *)CONF_type_win32;
    161 	conf->data = NULL;
    162 
    163 	return 1;
    164 	}
    165 
    166 static int def_destroy(CONF *conf)
    167 	{
    168 	if (def_destroy_data(conf))
    169 		{
    170 		OPENSSL_free(conf);
    171 		return 1;
    172 		}
    173 	return 0;
    174 	}
    175 
    176 static int def_destroy_data(CONF *conf)
    177 	{
    178 	if (conf == NULL)
    179 		return 0;
    180 	_CONF_free_data(conf);
    181 	return 1;
    182 	}
    183 
    184 static int def_load(CONF *conf, const char *name, long *line)
    185 	{
    186 	int ret;
    187 	BIO *in=NULL;
    188 
    189 #ifdef OPENSSL_SYS_VMS
    190 	in=BIO_new_file(name, "r");
    191 #else
    192 	in=BIO_new_file(name, "rb");
    193 #endif
    194 	if (in == NULL)
    195 		{
    196 		if (ERR_GET_REASON(ERR_peek_last_error()) == BIO_R_NO_SUCH_FILE)
    197 			CONFerr(CONF_F_DEF_LOAD,CONF_R_NO_SUCH_FILE);
    198 		else
    199 			CONFerr(CONF_F_DEF_LOAD,ERR_R_SYS_LIB);
    200 		return 0;
    201 		}
    202 
    203 	ret = def_load_bio(conf, in, line);
    204 	BIO_free(in);
    205 
    206 	return ret;
    207 	}
    208 
    209 static int def_load_bio(CONF *conf, BIO *in, long *line)
    210 	{
    211 /* The macro BUFSIZE conflicts with a system macro in VxWorks */
    212 #define CONFBUFSIZE	512
    213 	int bufnum=0,i,ii;
    214 	BUF_MEM *buff=NULL;
    215 	char *s,*p,*end;
    216 	int again,n;
    217 	long eline=0;
    218 	char btmp[DECIMAL_SIZE(eline)+1];
    219 	CONF_VALUE *v=NULL,*tv;
    220 	CONF_VALUE *sv=NULL;
    221 	char *section=NULL,*buf;
    222 	STACK_OF(CONF_VALUE) *section_sk=NULL,*ts;
    223 	char *start,*psection,*pname;
    224 	void *h = (void *)(conf->data);
    225 
    226 	if ((buff=BUF_MEM_new()) == NULL)
    227 		{
    228 		CONFerr(CONF_F_DEF_LOAD_BIO,ERR_R_BUF_LIB);
    229 		goto err;
    230 		}
    231 
    232 	section=(char *)OPENSSL_malloc(10);
    233 	if (section == NULL)
    234 		{
    235 		CONFerr(CONF_F_DEF_LOAD_BIO,ERR_R_MALLOC_FAILURE);
    236 		goto err;
    237 		}
    238 	BUF_strlcpy(section,"default",10);
    239 
    240 	if (_CONF_new_data(conf) == 0)
    241 		{
    242 		CONFerr(CONF_F_DEF_LOAD_BIO,ERR_R_MALLOC_FAILURE);
    243 		goto err;
    244 		}
    245 
    246 	sv=_CONF_new_section(conf,section);
    247 	if (sv == NULL)
    248 		{
    249 		CONFerr(CONF_F_DEF_LOAD_BIO,
    250 					CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
    251 		goto err;
    252 		}
    253 	section_sk=(STACK_OF(CONF_VALUE) *)sv->value;
    254 
    255 	bufnum=0;
    256 	again=0;
    257 	for (;;)
    258 		{
    259 		if (!BUF_MEM_grow(buff,bufnum+CONFBUFSIZE))
    260 			{
    261 			CONFerr(CONF_F_DEF_LOAD_BIO,ERR_R_BUF_LIB);
    262 			goto err;
    263 			}
    264 		p= &(buff->data[bufnum]);
    265 		*p='\0';
    266 		BIO_gets(in, p, CONFBUFSIZE-1);
    267 		p[CONFBUFSIZE-1]='\0';
    268 		ii=i=strlen(p);
    269 		if (i == 0 && !again) break;
    270 		again=0;
    271 		while (i > 0)
    272 			{
    273 			if ((p[i-1] != '\r') && (p[i-1] != '\n'))
    274 				break;
    275 			else
    276 				i--;
    277 			}
    278 		/* we removed some trailing stuff so there is a new
    279 		 * line on the end. */
    280 		if (ii && i == ii)
    281 			again=1; /* long line */
    282 		else
    283 			{
    284 			p[i]='\0';
    285 			eline++; /* another input line */
    286 			}
    287 
    288 		/* we now have a line with trailing \r\n removed */
    289 
    290 		/* i is the number of bytes */
    291 		bufnum+=i;
    292 
    293 		v=NULL;
    294 		/* check for line continuation */
    295 		if (bufnum >= 1)
    296 			{
    297 			/* If we have bytes and the last char '\\' and
    298 			 * second last char is not '\\' */
    299 			p= &(buff->data[bufnum-1]);
    300 			if (IS_ESC(conf,p[0]) &&
    301 				((bufnum <= 1) || !IS_ESC(conf,p[-1])))
    302 				{
    303 				bufnum--;
    304 				again=1;
    305 				}
    306 			}
    307 		if (again) continue;
    308 		bufnum=0;
    309 		buf=buff->data;
    310 
    311 		clear_comments(conf, buf);
    312 		n=strlen(buf);
    313 		s=eat_ws(conf, buf);
    314 		if (IS_EOF(conf,*s)) continue; /* blank line */
    315 		if (*s == '[')
    316 			{
    317 			char *ss;
    318 
    319 			s++;
    320 			start=eat_ws(conf, s);
    321 			ss=start;
    322 again:
    323 			end=eat_alpha_numeric(conf, ss);
    324 			p=eat_ws(conf, end);
    325 			if (*p != ']')
    326 				{
    327 				if (*p != '\0')
    328 					{
    329 					ss=p;
    330 					goto again;
    331 					}
    332 				CONFerr(CONF_F_DEF_LOAD_BIO,
    333 					CONF_R_MISSING_CLOSE_SQUARE_BRACKET);
    334 				goto err;
    335 				}
    336 			*end='\0';
    337 			if (!str_copy(conf,NULL,&section,start)) goto err;
    338 			if ((sv=_CONF_get_section(conf,section)) == NULL)
    339 				sv=_CONF_new_section(conf,section);
    340 			if (sv == NULL)
    341 				{
    342 				CONFerr(CONF_F_DEF_LOAD_BIO,
    343 					CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
    344 				goto err;
    345 				}
    346 			section_sk=(STACK_OF(CONF_VALUE) *)sv->value;
    347 			continue;
    348 			}
    349 		else
    350 			{
    351 			pname=s;
    352 			psection=NULL;
    353 			end=eat_alpha_numeric(conf, s);
    354 			if ((end[0] == ':') && (end[1] == ':'))
    355 				{
    356 				*end='\0';
    357 				end+=2;
    358 				psection=pname;
    359 				pname=end;
    360 				end=eat_alpha_numeric(conf, end);
    361 				}
    362 			p=eat_ws(conf, end);
    363 			if (*p != '=')
    364 				{
    365 				CONFerr(CONF_F_DEF_LOAD_BIO,
    366 						CONF_R_MISSING_EQUAL_SIGN);
    367 				goto err;
    368 				}
    369 			*end='\0';
    370 			p++;
    371 			start=eat_ws(conf, p);
    372 			while (!IS_EOF(conf,*p))
    373 				p++;
    374 			p--;
    375 			while ((p != start) && (IS_WS(conf,*p)))
    376 				p--;
    377 			p++;
    378 			*p='\0';
    379 
    380 			if (!(v=(CONF_VALUE *)OPENSSL_malloc(sizeof(CONF_VALUE))))
    381 				{
    382 				CONFerr(CONF_F_DEF_LOAD_BIO,
    383 							ERR_R_MALLOC_FAILURE);
    384 				goto err;
    385 				}
    386 			if (psection == NULL) psection=section;
    387 			v->name=(char *)OPENSSL_malloc(strlen(pname)+1);
    388 			v->value=NULL;
    389 			if (v->name == NULL)
    390 				{
    391 				CONFerr(CONF_F_DEF_LOAD_BIO,
    392 							ERR_R_MALLOC_FAILURE);
    393 				goto err;
    394 				}
    395 			BUF_strlcpy(v->name,pname,strlen(pname)+1);
    396 			if (!str_copy(conf,psection,&(v->value),start)) goto err;
    397 
    398 			if (strcmp(psection,section) != 0)
    399 				{
    400 				if ((tv=_CONF_get_section(conf,psection))
    401 					== NULL)
    402 					tv=_CONF_new_section(conf,psection);
    403 				if (tv == NULL)
    404 					{
    405 					CONFerr(CONF_F_DEF_LOAD_BIO,
    406 					   CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
    407 					goto err;
    408 					}
    409 				ts=(STACK_OF(CONF_VALUE) *)tv->value;
    410 				}
    411 			else
    412 				{
    413 				tv=sv;
    414 				ts=section_sk;
    415 				}
    416 #if 1
    417 			if (_CONF_add_string(conf, tv, v) == 0)
    418 				{
    419 				CONFerr(CONF_F_DEF_LOAD_BIO,
    420 							ERR_R_MALLOC_FAILURE);
    421 				goto err;
    422 				}
    423 #else
    424 			v->section=tv->section;
    425 			if (!sk_CONF_VALUE_push(ts,v))
    426 				{
    427 				CONFerr(CONF_F_DEF_LOAD_BIO,
    428 							ERR_R_MALLOC_FAILURE);
    429 				goto err;
    430 				}
    431 			vv=(CONF_VALUE *)lh_insert(conf->data,v);
    432 			if (vv != NULL)
    433 				{
    434 				sk_CONF_VALUE_delete_ptr(ts,vv);
    435 				OPENSSL_free(vv->name);
    436 				OPENSSL_free(vv->value);
    437 				OPENSSL_free(vv);
    438 				}
    439 #endif
    440 			v=NULL;
    441 			}
    442 		}
    443 	if (buff != NULL) BUF_MEM_free(buff);
    444 	if (section != NULL) OPENSSL_free(section);
    445 	return(1);
    446 err:
    447 	if (buff != NULL) BUF_MEM_free(buff);
    448 	if (section != NULL) OPENSSL_free(section);
    449 	if (line != NULL) *line=eline;
    450 	BIO_snprintf(btmp,sizeof btmp,"%ld",eline);
    451 	ERR_add_error_data(2,"line ",btmp);
    452 	if ((h != conf->data) && (conf->data != NULL))
    453 		{
    454 		CONF_free(conf->data);
    455 		conf->data=NULL;
    456 		}
    457 	if (v != NULL)
    458 		{
    459 		if (v->name != NULL) OPENSSL_free(v->name);
    460 		if (v->value != NULL) OPENSSL_free(v->value);
    461 		if (v != NULL) OPENSSL_free(v);
    462 		}
    463 	return(0);
    464 	}
    465 
    466 static void clear_comments(CONF *conf, char *p)
    467 	{
    468 	char *to;
    469 
    470 	to=p;
    471 	for (;;)
    472 		{
    473 		if (IS_FCOMMENT(conf,*p))
    474 			{
    475 			*p='\0';
    476 			return;
    477 			}
    478 		if (!IS_WS(conf,*p))
    479 			{
    480 			break;
    481 			}
    482 		p++;
    483 		}
    484 
    485 	for (;;)
    486 		{
    487 		if (IS_COMMENT(conf,*p))
    488 			{
    489 			*p='\0';
    490 			return;
    491 			}
    492 		if (IS_DQUOTE(conf,*p))
    493 			{
    494 			p=scan_dquote(conf, p);
    495 			continue;
    496 			}
    497 		if (IS_QUOTE(conf,*p))
    498 			{
    499 			p=scan_quote(conf, p);
    500 			continue;
    501 			}
    502 		if (IS_ESC(conf,*p))
    503 			{
    504 			p=scan_esc(conf,p);
    505 			continue;
    506 			}
    507 		if (IS_EOF(conf,*p))
    508 			return;
    509 		else
    510 			p++;
    511 		}
    512 	}
    513 
    514 static int str_copy(CONF *conf, char *section, char **pto, char *from)
    515 	{
    516 	int q,r,rr=0,to=0,len=0;
    517 	char *s,*e,*rp,*p,*rrp,*np,*cp,v;
    518 	BUF_MEM *buf;
    519 
    520 	if ((buf=BUF_MEM_new()) == NULL) return(0);
    521 
    522 	len=strlen(from)+1;
    523 	if (!BUF_MEM_grow(buf,len)) goto err;
    524 
    525 	for (;;)
    526 		{
    527 		if (IS_QUOTE(conf,*from))
    528 			{
    529 			q= *from;
    530 			from++;
    531 			while (!IS_EOF(conf,*from) && (*from != q))
    532 				{
    533 				if (IS_ESC(conf,*from))
    534 					{
    535 					from++;
    536 					if (IS_EOF(conf,*from)) break;
    537 					}
    538 				buf->data[to++]= *(from++);
    539 				}
    540 			if (*from == q) from++;
    541 			}
    542 		else if (IS_DQUOTE(conf,*from))
    543 			{
    544 			q= *from;
    545 			from++;
    546 			while (!IS_EOF(conf,*from))
    547 				{
    548 				if (*from == q)
    549 					{
    550 					if (*(from+1) == q)
    551 						{
    552 						from++;
    553 						}
    554 					else
    555 						{
    556 						break;
    557 						}
    558 					}
    559 				buf->data[to++]= *(from++);
    560 				}
    561 			if (*from == q) from++;
    562 			}
    563 		else if (IS_ESC(conf,*from))
    564 			{
    565 			from++;
    566 			v= *(from++);
    567 			if (IS_EOF(conf,v)) break;
    568 			else if (v == 'r') v='\r';
    569 			else if (v == 'n') v='\n';
    570 			else if (v == 'b') v='\b';
    571 			else if (v == 't') v='\t';
    572 			buf->data[to++]= v;
    573 			}
    574 		else if (IS_EOF(conf,*from))
    575 			break;
    576 		else if (*from == '$')
    577 			{
    578 			/* try to expand it */
    579 			rrp=NULL;
    580 			s= &(from[1]);
    581 			if (*s == '{')
    582 				q='}';
    583 			else if (*s == '(')
    584 				q=')';
    585 			else q=0;
    586 
    587 			if (q) s++;
    588 			cp=section;
    589 			e=np=s;
    590 			while (IS_ALPHA_NUMERIC(conf,*e))
    591 				e++;
    592 			if ((e[0] == ':') && (e[1] == ':'))
    593 				{
    594 				cp=np;
    595 				rrp=e;
    596 				rr= *e;
    597 				*rrp='\0';
    598 				e+=2;
    599 				np=e;
    600 				while (IS_ALPHA_NUMERIC(conf,*e))
    601 					e++;
    602 				}
    603 			r= *e;
    604 			*e='\0';
    605 			rp=e;
    606 			if (q)
    607 				{
    608 				if (r != q)
    609 					{
    610 					CONFerr(CONF_F_STR_COPY,CONF_R_NO_CLOSE_BRACE);
    611 					goto err;
    612 					}
    613 				e++;
    614 				}
    615 			/* So at this point we have
    616 			 * np which is the start of the name string which is
    617 			 *   '\0' terminated.
    618 			 * cp which is the start of the section string which is
    619 			 *   '\0' terminated.
    620 			 * e is the 'next point after'.
    621 			 * r and rr are the chars replaced by the '\0'
    622 			 * rp and rrp is where 'r' and 'rr' came from.
    623 			 */
    624 			p=_CONF_get_string(conf,cp,np);
    625 			if (rrp != NULL) *rrp=rr;
    626 			*rp=r;
    627 			if (p == NULL)
    628 				{
    629 				CONFerr(CONF_F_STR_COPY,CONF_R_VARIABLE_HAS_NO_VALUE);
    630 				goto err;
    631 				}
    632 			BUF_MEM_grow_clean(buf,(strlen(p)+buf->length-(e-from)));
    633 			while (*p)
    634 				buf->data[to++]= *(p++);
    635 
    636 			/* Since we change the pointer 'from', we also have
    637 			   to change the perceived length of the string it
    638 			   points at.  /RL */
    639 			len -= e-from;
    640 			from=e;
    641 
    642 			/* In case there were no braces or parenthesis around
    643 			   the variable reference, we have to put back the
    644 			   character that was replaced with a '\0'.  /RL */
    645 			*rp = r;
    646 			}
    647 		else
    648 			buf->data[to++]= *(from++);
    649 		}
    650 	buf->data[to]='\0';
    651 	if (*pto != NULL) OPENSSL_free(*pto);
    652 	*pto=buf->data;
    653 	OPENSSL_free(buf);
    654 	return(1);
    655 err:
    656 	if (buf != NULL) BUF_MEM_free(buf);
    657 	return(0);
    658 	}
    659 
    660 static char *eat_ws(CONF *conf, char *p)
    661 	{
    662 	while (IS_WS(conf,*p) && (!IS_EOF(conf,*p)))
    663 		p++;
    664 	return(p);
    665 	}
    666 
    667 static char *eat_alpha_numeric(CONF *conf, char *p)
    668 	{
    669 	for (;;)
    670 		{
    671 		if (IS_ESC(conf,*p))
    672 			{
    673 			p=scan_esc(conf,p);
    674 			continue;
    675 			}
    676 		if (!IS_ALPHA_NUMERIC_PUNCT(conf,*p))
    677 			return(p);
    678 		p++;
    679 		}
    680 	}
    681 
    682 static char *scan_quote(CONF *conf, char *p)
    683 	{
    684 	int q= *p;
    685 
    686 	p++;
    687 	while (!(IS_EOF(conf,*p)) && (*p != q))
    688 		{
    689 		if (IS_ESC(conf,*p))
    690 			{
    691 			p++;
    692 			if (IS_EOF(conf,*p)) return(p);
    693 			}
    694 		p++;
    695 		}
    696 	if (*p == q) p++;
    697 	return(p);
    698 	}
    699 
    700 
    701 static char *scan_dquote(CONF *conf, char *p)
    702 	{
    703 	int q= *p;
    704 
    705 	p++;
    706 	while (!(IS_EOF(conf,*p)))
    707 		{
    708 		if (*p == q)
    709 			{
    710 			if (*(p+1) == q)
    711 				{
    712 				p++;
    713 				}
    714 			else
    715 				{
    716 				break;
    717 				}
    718 			}
    719 		p++;
    720 		}
    721 	if (*p == q) p++;
    722 	return(p);
    723 	}
    724 
    725 static void dump_value_doall_arg(CONF_VALUE *a, BIO *out)
    726 	{
    727 	if (a->name)
    728 		BIO_printf(out, "[%s] %s=%s\n", a->section, a->name, a->value);
    729 	else
    730 		BIO_printf(out, "[[%s]]\n", a->section);
    731 	}
    732 
    733 static IMPLEMENT_LHASH_DOALL_ARG_FN(dump_value, CONF_VALUE, BIO)
    734 
    735 static int def_dump(const CONF *conf, BIO *out)
    736 	{
    737 	lh_CONF_VALUE_doall_arg(conf->data, LHASH_DOALL_ARG_FN(dump_value),
    738 				BIO, out);
    739 	return 1;
    740 	}
    741 
    742 static int def_is_number(const CONF *conf, char c)
    743 	{
    744 	return IS_NUMBER(conf,c);
    745 	}
    746 
    747 static int def_to_int(const CONF *conf, char c)
    748 	{
    749 	return c - '0';
    750 	}
    751 
    752