xref: /minix3/crypto/external/bsd/libsaslc/dist/src/parser.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /* $NetBSD: parser.c,v 1.5 2015/08/08 12:34:33 shm Exp $ */
2ebfedea0SLionel Sambuc 
3ebfedea0SLionel Sambuc /* Copyright (c) 2010 The NetBSD Foundation, Inc.
4ebfedea0SLionel Sambuc  * All rights reserved.
5ebfedea0SLionel Sambuc  *
6ebfedea0SLionel Sambuc  * This code is derived from software contributed to The NetBSD Foundation
7ebfedea0SLionel Sambuc  * by Mateusz Kocielski.
8ebfedea0SLionel Sambuc  *
9ebfedea0SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
10ebfedea0SLionel Sambuc  * modification, are permitted provided that the following conditions
11ebfedea0SLionel Sambuc  * are met:
12ebfedea0SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
13ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
14ebfedea0SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
15ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
16ebfedea0SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
17ebfedea0SLionel Sambuc  * 3. All advertising materials mentioning features or use of this software
18ebfedea0SLionel Sambuc  *    must display the following acknowledgement:
19ebfedea0SLionel Sambuc  *  	  This product includes software developed by the NetBSD
20ebfedea0SLionel Sambuc  *  	  Foundation, Inc. and its contributors.
21ebfedea0SLionel Sambuc  * 4. Neither the name of The NetBSD Foundation nor the names of its
22ebfedea0SLionel Sambuc  *    contributors may be used to endorse or promote products derived
23ebfedea0SLionel Sambuc  *    from this software without specific prior written permission.
24ebfedea0SLionel Sambuc  *
25ebfedea0SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
26ebfedea0SLionel Sambuc  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27ebfedea0SLionel Sambuc  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28ebfedea0SLionel Sambuc  * PURPOSE ARE DISCLAIMED.	IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
29ebfedea0SLionel Sambuc  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30ebfedea0SLionel Sambuc  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31ebfedea0SLionel Sambuc  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32ebfedea0SLionel Sambuc  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33ebfedea0SLionel Sambuc  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34ebfedea0SLionel Sambuc  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35ebfedea0SLionel Sambuc  * POSSIBILITY OF SUCH DAMAGE.
36ebfedea0SLionel Sambuc  */
37ebfedea0SLionel Sambuc #include <sys/cdefs.h>
38*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: parser.c,v 1.5 2015/08/08 12:34:33 shm Exp $");
39ebfedea0SLionel Sambuc 
40ebfedea0SLionel Sambuc #include <sys/stat.h>
41ebfedea0SLionel Sambuc #include <sys/syslimits.h>	/* for PATH_MAX */
42ebfedea0SLionel Sambuc 
43ebfedea0SLionel Sambuc #include <ctype.h>
44ebfedea0SLionel Sambuc #include <err.h>
45ebfedea0SLionel Sambuc #include <errno.h>
46ebfedea0SLionel Sambuc #include <saslc.h>
47ebfedea0SLionel Sambuc #include <stdio.h>
48ebfedea0SLionel Sambuc #include <stdlib.h>
49ebfedea0SLionel Sambuc #include <string.h>
50ebfedea0SLionel Sambuc 
51ebfedea0SLionel Sambuc #include "dict.h"
52ebfedea0SLionel Sambuc #include "msg.h"
53ebfedea0SLionel Sambuc #include "parser.h"
54ebfedea0SLionel Sambuc #include "saslc_private.h"
55ebfedea0SLionel Sambuc 
56ebfedea0SLionel Sambuc #define SASLC__COMMENT_CHAR	'#'
57ebfedea0SLionel Sambuc 
58ebfedea0SLionel Sambuc /* config file location defines */
59ebfedea0SLionel Sambuc #define SASLC__CONFIG_PATH		"/etc/saslc.d"
60ebfedea0SLionel Sambuc #define SASLC__CONFIG_MAIN_FILE		"saslc"
61ebfedea0SLionel Sambuc #define SASLC__CONFIG_MECH_DIRECTORY	"mech"
62ebfedea0SLionel Sambuc #define SASLC__CONFIG_SUFFIX		".conf"
63ebfedea0SLionel Sambuc #define SASLC__DEFAULT_APPNAME		"saslc"
64ebfedea0SLionel Sambuc 
65ebfedea0SLionel Sambuc /* token types */
66ebfedea0SLionel Sambuc enum {
67ebfedea0SLionel Sambuc 	TOKEN_KEY,		/* option (key) */
68ebfedea0SLionel Sambuc 	TOKEN_STRING,		/* quoted string */
69ebfedea0SLionel Sambuc 	TOKEN_NUM,		/* number */
70ebfedea0SLionel Sambuc 	TOKEN_COMMENT,		/* comment character */
71ebfedea0SLionel Sambuc 	TOKEN_UNKNOWN		/* unknown */
72ebfedea0SLionel Sambuc };
73ebfedea0SLionel Sambuc 
74ebfedea0SLionel Sambuc /* token structure */
75ebfedea0SLionel Sambuc typedef struct saslc__token_t {
76ebfedea0SLionel Sambuc 	int type;		/**< token type */
77ebfedea0SLionel Sambuc 	char *val;		/**< token string value */
78ebfedea0SLionel Sambuc } saslc__token_t;
79ebfedea0SLionel Sambuc 
80ebfedea0SLionel Sambuc static inline char *
skip_WS(char * p)81ebfedea0SLionel Sambuc skip_WS(char *p)
82ebfedea0SLionel Sambuc {
83ebfedea0SLionel Sambuc 
84ebfedea0SLionel Sambuc 	while (*p == ' ' || *p == '\t')
85ebfedea0SLionel Sambuc 		p++;
86ebfedea0SLionel Sambuc 	return p;
87ebfedea0SLionel Sambuc }
88ebfedea0SLionel Sambuc 
89ebfedea0SLionel Sambuc /**
90ebfedea0SLionel Sambuc  * @brief gets token from string c and updates pointer position.
91ebfedea0SLionel Sambuc  * @param c pointer to string
92ebfedea0SLionel Sambuc  * @return token on success, NULL on failure (e.g. at end of string).
93ebfedea0SLionel Sambuc  * On success, c is updated to point on next token.  It's position is
94ebfedea0SLionel Sambuc  * undefined on failure.
95ebfedea0SLionel Sambuc  *
96ebfedea0SLionel Sambuc  * Note: A legal key begins with an isalpha(3) character and is
97ebfedea0SLionel Sambuc  * followed by isalnum(3) or '_' characters.
98ebfedea0SLionel Sambuc  */
99ebfedea0SLionel Sambuc static saslc__token_t *
saslc__parse_get_token(char ** c)100ebfedea0SLionel Sambuc saslc__parse_get_token(char **c)
101ebfedea0SLionel Sambuc {
102ebfedea0SLionel Sambuc 	saslc__token_t *token;
103ebfedea0SLionel Sambuc 	char *e;
104ebfedea0SLionel Sambuc 
105ebfedea0SLionel Sambuc 	*c = skip_WS(*c);
106ebfedea0SLionel Sambuc 	if (**c == '\0')
107ebfedea0SLionel Sambuc 		return NULL;
108ebfedea0SLionel Sambuc 
109ebfedea0SLionel Sambuc 	if ((token = calloc(1, sizeof(*token))) == NULL)
110ebfedea0SLionel Sambuc 		return NULL;
111ebfedea0SLionel Sambuc 
112ebfedea0SLionel Sambuc 	token->val = *c;
113ebfedea0SLionel Sambuc 
114ebfedea0SLionel Sambuc 	if (**c == SASLC__COMMENT_CHAR)
115ebfedea0SLionel Sambuc 		token->type = TOKEN_COMMENT;
116ebfedea0SLionel Sambuc 
117ebfedea0SLionel Sambuc 	else if (**c == '\"')
118ebfedea0SLionel Sambuc 		token->type = TOKEN_STRING;
119ebfedea0SLionel Sambuc 
120ebfedea0SLionel Sambuc 	else if (isdigit((unsigned char)**c))
121ebfedea0SLionel Sambuc 		token->type = TOKEN_NUM;
122ebfedea0SLionel Sambuc 
123ebfedea0SLionel Sambuc 	else if (isalpha((unsigned char)**c))
124ebfedea0SLionel Sambuc 		token->type = TOKEN_KEY;
125ebfedea0SLionel Sambuc 
126ebfedea0SLionel Sambuc 	else
127ebfedea0SLionel Sambuc 		token->type = TOKEN_UNKNOWN;
128ebfedea0SLionel Sambuc 
129ebfedea0SLionel Sambuc 	switch (token->type) {
130ebfedea0SLionel Sambuc 	case TOKEN_COMMENT:
131ebfedea0SLionel Sambuc 		break;
132ebfedea0SLionel Sambuc 	case TOKEN_NUM:
133ebfedea0SLionel Sambuc 		errno = 0;
134ebfedea0SLionel Sambuc 		(void)strtoll(*c, &e, 0);
135ebfedea0SLionel Sambuc 		if (errno != 0)
136ebfedea0SLionel Sambuc 			goto err;
137ebfedea0SLionel Sambuc 		*c = e;
138ebfedea0SLionel Sambuc 		break;
139ebfedea0SLionel Sambuc 	case TOKEN_KEY:
140ebfedea0SLionel Sambuc 		(*c)++;
141ebfedea0SLionel Sambuc 		while (isalnum((unsigned char)**c) || **c == '_')
142ebfedea0SLionel Sambuc 			(*c)++;
143ebfedea0SLionel Sambuc 		break;
144ebfedea0SLionel Sambuc 	case TOKEN_STRING:
145ebfedea0SLionel Sambuc 		token->val++;	/* skip initial '\"' */
146ebfedea0SLionel Sambuc 		(*c)++;
147ebfedea0SLionel Sambuc 		/*
148ebfedea0SLionel Sambuc 		 * XXX: should we allow escapes inside the string?
149ebfedea0SLionel Sambuc 		 */
150ebfedea0SLionel Sambuc 		while (**c != '\0' && **c != '\"')
151ebfedea0SLionel Sambuc 			(*c)++;
152ebfedea0SLionel Sambuc 		if (**c != '\"')
153ebfedea0SLionel Sambuc 			goto err;
154ebfedea0SLionel Sambuc 		**c = '\0';	/* kill trailing '\"' */
155ebfedea0SLionel Sambuc 		(*c)++;
156ebfedea0SLionel Sambuc 		break;
157ebfedea0SLionel Sambuc 	case TOKEN_UNKNOWN:
158ebfedea0SLionel Sambuc 		goto err;
159ebfedea0SLionel Sambuc 	}
160ebfedea0SLionel Sambuc 
161ebfedea0SLionel Sambuc 	if (isspace((unsigned char)**c))
162ebfedea0SLionel Sambuc 		*(*c)++ = '\0';
163ebfedea0SLionel Sambuc 	else if (**c == SASLC__COMMENT_CHAR)
164ebfedea0SLionel Sambuc 		**c = '\0';
165ebfedea0SLionel Sambuc 	else if (**c != '\0')
166ebfedea0SLionel Sambuc 		goto err;
167ebfedea0SLionel Sambuc 
168ebfedea0SLionel Sambuc 	return token;
169ebfedea0SLionel Sambuc  err:
170ebfedea0SLionel Sambuc 	free(token);
171ebfedea0SLionel Sambuc 	return NULL;
172ebfedea0SLionel Sambuc }
173ebfedea0SLionel Sambuc 
174ebfedea0SLionel Sambuc /**
175ebfedea0SLionel Sambuc  * @brief parses line and store result in dict.
176ebfedea0SLionel Sambuc  * @param line input line
177ebfedea0SLionel Sambuc  * @param dict dictionary in which parsed options will be stored
178ebfedea0SLionel Sambuc  * @return 0 on success, -1 on failure.
179ebfedea0SLionel Sambuc  */
180ebfedea0SLionel Sambuc static int
saslc__parse_line(char * line,saslc__dict_t * dict)181ebfedea0SLionel Sambuc saslc__parse_line(char *line, saslc__dict_t *dict)
182ebfedea0SLionel Sambuc {
183ebfedea0SLionel Sambuc 	saslc__dict_result_t rv;
184ebfedea0SLionel Sambuc 	saslc__token_t *t;
185ebfedea0SLionel Sambuc 	char *key;
186ebfedea0SLionel Sambuc 
187ebfedea0SLionel Sambuc 	key = NULL;
188ebfedea0SLionel Sambuc 	while ((t = saslc__parse_get_token(&line)) != NULL) {
189*0a6a1f1dSLionel Sambuc 		if (t->type == TOKEN_COMMENT) {
190*0a6a1f1dSLionel Sambuc 			free(t);
191ebfedea0SLionel Sambuc 			break;
192*0a6a1f1dSLionel Sambuc 		}
193ebfedea0SLionel Sambuc 
194ebfedea0SLionel Sambuc 		if (key == NULL) {  /* get the key */
195ebfedea0SLionel Sambuc 			if (t->type != TOKEN_KEY)
196ebfedea0SLionel Sambuc 				goto err;
197ebfedea0SLionel Sambuc 			key = t->val;
198ebfedea0SLionel Sambuc 		}
199ebfedea0SLionel Sambuc 		else {  /* get the value and insert in dictionary */
200ebfedea0SLionel Sambuc 			if (t->type != TOKEN_STRING && t->type != TOKEN_NUM)
201ebfedea0SLionel Sambuc 				goto err;
202ebfedea0SLionel Sambuc 			rv = saslc__dict_insert(dict, key, t->val);
203ebfedea0SLionel Sambuc 			if (rv != DICT_OK && rv != DICT_KEYEXISTS)
204ebfedea0SLionel Sambuc 				goto err;
205ebfedea0SLionel Sambuc 			key = NULL;
206ebfedea0SLionel Sambuc 		}
207ebfedea0SLionel Sambuc 		free(t);
208ebfedea0SLionel Sambuc 	}
209ebfedea0SLionel Sambuc 	if (*line != '\0')	/* processed entire line */
210ebfedea0SLionel Sambuc 		return -1;
211ebfedea0SLionel Sambuc 	if (key != NULL)	/* completed key/value cycle */
212ebfedea0SLionel Sambuc 		return -1;
213ebfedea0SLionel Sambuc 	return 0;
214ebfedea0SLionel Sambuc  err:
215ebfedea0SLionel Sambuc 	free(t);
216ebfedea0SLionel Sambuc 	return -1;
217ebfedea0SLionel Sambuc }
218ebfedea0SLionel Sambuc 
219ebfedea0SLionel Sambuc /**
220ebfedea0SLionel Sambuc  * @brief parses file and store result in dict
221ebfedea0SLionel Sambuc  * @param ctx saslc context
222ebfedea0SLionel Sambuc  * @param path path to the file
223ebfedea0SLionel Sambuc  * @param dict dictionary in which parsed options will be stored
224ebfedea0SLionel Sambuc  * @return 0 on success, -1 on failure.
225ebfedea0SLionel Sambuc  */
226ebfedea0SLionel Sambuc static int
saslc__parse_file(saslc_t * ctx,char * path,saslc__dict_t * dict)227ebfedea0SLionel Sambuc saslc__parse_file(saslc_t *ctx, char *path, saslc__dict_t *dict)
228ebfedea0SLionel Sambuc {
229ebfedea0SLionel Sambuc 	FILE *fp;
230ebfedea0SLionel Sambuc 	char *buf, *lbuf;
231ebfedea0SLionel Sambuc 	size_t len;
232ebfedea0SLionel Sambuc 	int rv;
233ebfedea0SLionel Sambuc 
234ebfedea0SLionel Sambuc 	if ((fp = fopen(path, "r")) == NULL) {
235ebfedea0SLionel Sambuc 		/* Don't fail if we can't open the file. */
236ebfedea0SLionel Sambuc 		saslc__msg_dbg("%s: fopen: %s: %s", __func__, path,
237ebfedea0SLionel Sambuc 		    strerror(errno));
238ebfedea0SLionel Sambuc 		return 0;
239ebfedea0SLionel Sambuc 	}
240ebfedea0SLionel Sambuc 	saslc__msg_dbg("%s: parsing: \"%s\"", __func__, path);
241ebfedea0SLionel Sambuc 	rv = 0;
242ebfedea0SLionel Sambuc 	lbuf = NULL;
243ebfedea0SLionel Sambuc 	while ((buf = fgetln(fp, &len)) != NULL) {
244ebfedea0SLionel Sambuc 		if (buf[len - 1] == '\n')
245ebfedea0SLionel Sambuc 			buf[len - 1] = '\0';
246ebfedea0SLionel Sambuc 		else {
247ebfedea0SLionel Sambuc 			if ((lbuf = malloc(len + 1)) == NULL) {
248ebfedea0SLionel Sambuc 				saslc__error_set(ERR(ctx), ERROR_NOMEM, NULL);
249ebfedea0SLionel Sambuc 				rv = -1;
250ebfedea0SLionel Sambuc 				break;
251ebfedea0SLionel Sambuc 			}
252ebfedea0SLionel Sambuc 			memcpy(lbuf, buf, len);
253ebfedea0SLionel Sambuc 			lbuf[len] = '\0';
254ebfedea0SLionel Sambuc 			buf = lbuf;
255ebfedea0SLionel Sambuc 		}
256ebfedea0SLionel Sambuc 		if (saslc__parse_line(buf, dict) == -1) {
257ebfedea0SLionel Sambuc 			saslc__error_set(ERR(ctx), ERROR_PARSE,
258ebfedea0SLionel Sambuc 			    "can't parse file");
259ebfedea0SLionel Sambuc 			rv = -1;
260ebfedea0SLionel Sambuc 			break;
261ebfedea0SLionel Sambuc 		}
262ebfedea0SLionel Sambuc 		if (lbuf != NULL) {
263ebfedea0SLionel Sambuc 			free(lbuf);
264ebfedea0SLionel Sambuc 			lbuf = NULL;
265ebfedea0SLionel Sambuc 		}
266ebfedea0SLionel Sambuc 	}
267ebfedea0SLionel Sambuc 	if (lbuf != NULL)
268ebfedea0SLionel Sambuc 		free(lbuf);
269ebfedea0SLionel Sambuc 
270ebfedea0SLionel Sambuc 	fclose(fp);
271ebfedea0SLionel Sambuc 	return rv;
272ebfedea0SLionel Sambuc }
273ebfedea0SLionel Sambuc 
274ebfedea0SLionel Sambuc /**
275ebfedea0SLionel Sambuc  * @brief determine if a string indicates true or not.
276ebfedea0SLionel Sambuc  * @return true if the string is "true", "yes", or any nonzero
277ebfedea0SLionel Sambuc  * integer; false otherwise.
278ebfedea0SLionel Sambuc  *
279ebfedea0SLionel Sambuc  * XXX: does this really belong here?  Used in parser.c and xsess.c.
280ebfedea0SLionel Sambuc  */
281ebfedea0SLionel Sambuc bool
saslc__parser_is_true(const char * str)282ebfedea0SLionel Sambuc saslc__parser_is_true(const char *str)
283ebfedea0SLionel Sambuc {
284ebfedea0SLionel Sambuc 	static const char *true_str[] = {
285ebfedea0SLionel Sambuc 		"true",
286ebfedea0SLionel Sambuc 		"yes"
287ebfedea0SLionel Sambuc 	};
288ebfedea0SLionel Sambuc 	char *e;
289ebfedea0SLionel Sambuc 	size_t i;
290ebfedea0SLionel Sambuc 	long int val;
291ebfedea0SLionel Sambuc 
292ebfedea0SLionel Sambuc 	if (str == NULL)
293ebfedea0SLionel Sambuc 		return false;
294ebfedea0SLionel Sambuc 
295ebfedea0SLionel Sambuc 	val = strtol(str, &e, 0);
296ebfedea0SLionel Sambuc 	if (*str != '\0' && *e == '\0')
297ebfedea0SLionel Sambuc 		return val != 0;
298ebfedea0SLionel Sambuc 
299ebfedea0SLionel Sambuc 	for (i = 0; i < __arraycount(true_str); i++)
300ebfedea0SLionel Sambuc 		if (strcasecmp(str, true_str[i]) == 0)
301ebfedea0SLionel Sambuc 			return true;
302ebfedea0SLionel Sambuc 
303ebfedea0SLionel Sambuc 	return false;
304ebfedea0SLionel Sambuc }
305ebfedea0SLionel Sambuc 
306ebfedea0SLionel Sambuc /**
307ebfedea0SLionel Sambuc  * @brief parse configuration files. By default function reads
308ebfedea0SLionel Sambuc  * files from /etc/saslc.d/saslc/ directory if appname is not setup. Otherwise
309ebfedea0SLionel Sambuc  * function uses /etc/saslc.d/[appname]/ directory. /etc/saslc.d/ is default
310ebfedea0SLionel Sambuc  * directory which stores configuration for all applications, but can be
311ebfedea0SLionel Sambuc  * overwritten by SASLC_CONFIG variable in environment.
312ebfedea0SLionel Sambuc  * @param ctx saslc context
313ebfedea0SLionel Sambuc  * @return 0 on success, -1 on failure.
314ebfedea0SLionel Sambuc  */
315ebfedea0SLionel Sambuc int
saslc__parser_config(saslc_t * ctx)316ebfedea0SLionel Sambuc saslc__parser_config(saslc_t *ctx)
317ebfedea0SLionel Sambuc {
318ebfedea0SLionel Sambuc 	char path[PATH_MAX + 1];
319ebfedea0SLionel Sambuc 	struct stat sb;
320ebfedea0SLionel Sambuc 	saslc__mech_list_node_t *mech_node;
321ebfedea0SLionel Sambuc 	const char *config_path, *debug, *appname;
322ebfedea0SLionel Sambuc 
323ebfedea0SLionel Sambuc 	config_path = ctx->pathname;
324ebfedea0SLionel Sambuc 	if (config_path == NULL)
325ebfedea0SLionel Sambuc 		config_path = getenv(SASLC_ENV_CONFIG);
326ebfedea0SLionel Sambuc 	if (config_path == NULL)
327ebfedea0SLionel Sambuc 		config_path = SASLC__CONFIG_PATH;
328ebfedea0SLionel Sambuc 
329ebfedea0SLionel Sambuc 	if (stat(config_path, &sb) == -1 || !S_ISDIR(sb.st_mode)) {
330ebfedea0SLionel Sambuc 		/* XXX: should this be fatal or silently ignored? */
331ebfedea0SLionel Sambuc 		saslc__msg_err("%s: stat: config_path='%s': %s", __func__,
332ebfedea0SLionel Sambuc 		    config_path, strerror(errno));
333ebfedea0SLionel Sambuc 		return 0;
334ebfedea0SLionel Sambuc 	}
335ebfedea0SLionel Sambuc 
336ebfedea0SLionel Sambuc 	if ((appname = ctx->appname) == NULL)
337ebfedea0SLionel Sambuc 		appname = SASLC__DEFAULT_APPNAME;
338ebfedea0SLionel Sambuc 
339ebfedea0SLionel Sambuc 	/* parse global config file */
340ebfedea0SLionel Sambuc 	snprintf(path, sizeof(path), "%s/%s/%s%s", config_path,
341ebfedea0SLionel Sambuc 	    appname, SASLC__CONFIG_MAIN_FILE, SASLC__CONFIG_SUFFIX);
342ebfedea0SLionel Sambuc 	if (saslc__parse_file(ctx, path, ctx->prop) == -1)
343ebfedea0SLionel Sambuc 		return -1;
344ebfedea0SLionel Sambuc 
345ebfedea0SLionel Sambuc 	/* XXX: check this as early as possible! */
346ebfedea0SLionel Sambuc 	debug = saslc__dict_get(ctx->prop, SASLC_PROP_DEBUG);
347ebfedea0SLionel Sambuc 	if (debug != NULL)
348ebfedea0SLionel Sambuc 		saslc_debug = saslc__parser_is_true(debug);
349ebfedea0SLionel Sambuc 
350ebfedea0SLionel Sambuc 	/* parse mechanism config files */
351ebfedea0SLionel Sambuc 	LIST_FOREACH(mech_node, ctx->mechanisms, nodes) {
352ebfedea0SLionel Sambuc 		snprintf(path, sizeof(path), "%s/%s/%s/%s%s",
353ebfedea0SLionel Sambuc 		    config_path, appname, SASLC__CONFIG_MECH_DIRECTORY,
354ebfedea0SLionel Sambuc 		    mech_node->mech->name, SASLC__CONFIG_SUFFIX);
355ebfedea0SLionel Sambuc 		if (saslc__parse_file(ctx, path, mech_node->prop) == -1)
356ebfedea0SLionel Sambuc 			return -1;
357ebfedea0SLionel Sambuc 	}
358ebfedea0SLionel Sambuc 
359ebfedea0SLionel Sambuc 	return 0;
360ebfedea0SLionel Sambuc }
361