xref: /illumos-gate/usr/src/cmd/nscd/nscd_cfgfile.c (revision f67ca41a3fe371a8ac34045eb45b3c5449ee601c)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  *   routine to read configuration file
30  *
31  */
32 #include "nscd_config.h"
33 #include "nscd_log.h"
34 #include <locale.h>
35 #include <ctype.h>
36 #include <string.h>
37 #include <errno.h>
38 
39 static int
40 strbreak(char *field[], int array_size, char *s, char *sep)
41 {
42 	int	i;
43 	char	*lasts, *qp;
44 	int	inquote;
45 
46 	qp = strchr(s, '"');
47 	for (i = 0; i < array_size && (field[i] =
48 		strtok_r((i?(char *)NULL:s), sep, &lasts)); i++);
49 
50 	if (qp == NULL)
51 		return (i);
52 
53 	inquote = 1;
54 	while (++qp < lasts) {
55 
56 		switch (*qp) {
57 
58 		case '"':
59 			inquote = (inquote == 0);
60 			break;
61 
62 		case '\\':
63 			/* escape " */
64 			if (inquote == 1 && *(qp + 1) == '"')
65 				qp++;
66 			break;
67 
68 		case '\0':
69 			if (inquote == 1) {
70 				*qp = ' ';
71 				i--;
72 			}
73 
74 			break;
75 		}
76 	}
77 
78 	return (i);
79 }
80 
81 
82 nscd_rc_t
83 _nscd_cfg_read_file(
84 	char			*filename,
85 	nscd_cfg_error_t	**errorp)
86 {
87 	char			*me = "_nscd_cfg_read_file";
88 	FILE			*in;
89 	char			buffer[255];
90 	char			*fields [128];
91 	int			linecnt;
92 	int			fieldcnt;
93 	nscd_rc_t		rc = NSCD_SUCCESS;
94 	nscd_cfg_handle_t	*h = NULL;
95 	nscd_cfg_param_desc_t	*pdesc;
96 	char			*dbname, *str;
97 	void			*data_p;
98 	int			i;
99 	char			msg[NSCD_CFG_MAX_ERR_MSG_LEN];
100 
101 	union {
102 		int	i;
103 		char	data[256];
104 	} u;
105 
106 	if ((in = fopen(filename, "r")) == NULL) {
107 
108 		(void) snprintf(msg, sizeof (msg),
109 	gettext("open of configuration file \"%s\" failed: %s"),
110 			filename, strerror(errno));
111 		if (errorp != NULL)
112 			*errorp = _nscd_cfg_make_error(
113 				NSCD_CFG_FILE_OPEN_ERROR, msg);
114 
115 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
116 		(me, "%s\n", msg);
117 
118 		return (NSCD_CFG_FILE_OPEN_ERROR);
119 	}
120 
121 	linecnt = 0;
122 	msg[0] = '\0';
123 	while (fgets(buffer, sizeof (buffer), in) != NULL) {
124 
125 		linecnt++;
126 		if ((fieldcnt = strbreak(fields, 128, buffer, " \t\n")) ==
127 				0 || *fields[0] == '#') {
128 			/* skip blank or comment lines */
129 			continue;
130 		}
131 
132 		switch (fieldcnt) {
133 
134 		case 2:
135 			dbname = NULL;
136 			str = fields[1];
137 			break;
138 
139 		case 3:
140 			dbname = fields[1];
141 			str = fields[2];
142 			break;
143 
144 		default:
145 
146 			(void) strlcpy(u.data, fields[0], sizeof (u.data));
147 			for (i = 1; i < fieldcnt; i++) {
148 				(void) strlcat(u.data, " ",
149 					sizeof (u.data));
150 				(void) strlcat(u.data, fields[i],
151 					sizeof (u.data));
152 			}
153 
154 			(void) snprintf(msg, sizeof (msg),
155 		gettext("Syntax error: line %d of configuration "
156 			"file: %s : \"%s\""), linecnt, filename, u.data);
157 			if (errorp != NULL)
158 				*errorp = _nscd_cfg_make_error(
159 					NSCD_CFG_SYNTAX_ERROR, msg);
160 
161 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
162 			(me, "%s\n", msg);
163 
164 			rc = NSCD_CFG_SYNTAX_ERROR;
165 			break;
166 		}
167 
168 		if (rc != NSCD_SUCCESS)
169 			break;
170 
171 		rc = _nscd_cfg_get_handle(fields[0], dbname, &h, errorp);
172 		if (rc != NSCD_SUCCESS)
173 			break;
174 
175 		pdesc = _nscd_cfg_get_desc(h);
176 
177 		/* convert string to data */
178 		rc = _nscd_cfg_str_to_data(pdesc, str, &u.data,
179 			&data_p, errorp);
180 		if (rc != NSCD_SUCCESS)
181 			break;
182 
183 		/* do preliminary check based on data type */
184 		rc = _nscd_cfg_prelim_check(pdesc, data_p, errorp);
185 		if (rc != NSCD_SUCCESS)
186 			break;
187 
188 		rc = _nscd_cfg_set_linked(h, data_p, errorp);
189 		_nscd_cfg_free_handle(h);
190 		h = NULL;
191 		if (rc != NSCD_CFG_READ_ONLY && rc != NSCD_SUCCESS)
192 			break;
193 		else {
194 			_nscd_cfg_free_error(*errorp);
195 			*errorp = NULL;
196 		}
197 	}
198 	/* NSCD_CFG_READ_ONLY is not fatal */
199 	if (rc == NSCD_CFG_READ_ONLY)
200 		rc = NSCD_SUCCESS;
201 
202 	if (h != NULL)
203 		_nscd_cfg_free_handle(h);
204 
205 	(void) fclose(in);
206 
207 	if (msg[0] == '\0' && rc != NSCD_SUCCESS) {
208 		if (errorp != NULL)
209 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
210 			(me, "%s\n", NSCD_ERR2MSG(*errorp));
211 	}
212 
213 	return (rc);
214 }
215 
216 nscd_rc_t
217 _nscd_cfg_read_nsswitch_file(
218 	char			*filename,
219 	nscd_cfg_error_t	**errorp)
220 {
221 	char			*me = "_nscd_cfg_read_nsswitch_file";
222 	char			*pname = "nsw-config-string";
223 	FILE			*in;
224 	char			buffer[255];
225 	char			*cc, *ce, *ce1, *c1, *c2;
226 	char			*db, *dbe;
227 	char			*nsscfg;
228 	int			syntax_err;
229 	int			linecnt;
230 	nscd_rc_t		rc = NSCD_SUCCESS;
231 	nscd_cfg_handle_t	*h = NULL;
232 	nscd_cfg_param_desc_t	*pdesc;
233 	void			*data_p;
234 	char			msg[NSCD_CFG_MAX_ERR_MSG_LEN];
235 
236 	union {
237 		int	i;
238 		char	data[256];
239 	} u;
240 
241 	if ((in = fopen(filename, "r")) == NULL) {
242 
243 		(void) snprintf(msg, sizeof (msg),
244 	gettext("open of configuration file \"%s\" failed: %s"),
245 			filename, strerror(errno));
246 		if (errorp != NULL)
247 			*errorp = _nscd_cfg_make_error(
248 				NSCD_CFG_FILE_OPEN_ERROR, msg);
249 
250 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
251 		(me, "%s\n", msg);
252 
253 		return (NSCD_CFG_FILE_OPEN_ERROR);
254 	}
255 
256 	linecnt = 0;
257 	msg[0] = '\0';
258 	while (fgets(buffer, sizeof (buffer), in) != NULL) {
259 
260 		linecnt++;
261 		syntax_err = 0;
262 		/* skip blank or comment lines */
263 		if (buffer[0] == '#' || buffer[0] == '\n')
264 			continue;
265 		/* skip end of line comment */
266 		if ((ce = strchr(buffer, '\n')) != NULL)
267 			*ce = '\0';
268 		else
269 			ce = &buffer[255];
270 		if ((ce1 = strchr(buffer, '#')) != NULL) {
271 			ce = ce1;
272 			*ce = '\0';
273 		}
274 		if ((cc = strchr(buffer, ':')) == NULL) {
275 			c1 = buffer;
276 			while (isalpha(*c1) && c1 < ce)
277 				c1++;
278 			if (c1 > ce)
279 				syntax_err = 1;
280 			else /* blank line */
281 				continue;
282 		} else {
283 			/*
284 			 * data name goes before ':',
285 			 * skip spaces on both ends
286 			 */
287 			c2 = cc - 1;
288 			while (buffer <= c2 && isspace(*c2))
289 				c2--;
290 			c1 = buffer;
291 			while (c1 <= cc && isspace(*c1))
292 				c1++;
293 			if (c1 > c2)
294 				syntax_err = 1;
295 			else {
296 				db = c1;
297 				dbe = c2 + 1;
298 
299 				/*
300 				 * nss config goes after ':',
301 				 * skip spaces on both ends
302 				 */
303 				c1 = cc + 1;
304 				while (c1 <= ce && isspace(*c1))
305 					c1++;
306 				c2 = ce - 1;
307 				while (cc <= c2 && isspace(*c2))
308 					c2--;
309 				if (c1 > c2)
310 					syntax_err = 1;
311 				else {
312 					*dbe = '\0';
313 					nsscfg = c1;
314 					*(c2 + 1) = '\0';
315 				}
316 			}
317 		}
318 
319 		if (syntax_err == 1) {
320 
321 			(void) snprintf(msg, sizeof (msg),
322 		gettext("Syntax error: line %d of configuration "
323 			"file: %s : \"%s\""), linecnt, filename, buffer);
324 			if (errorp != NULL)
325 				*errorp = _nscd_cfg_make_error(
326 					NSCD_CFG_SYNTAX_ERROR, msg);
327 
328 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
329 			(me, "%s\n", msg);
330 
331 			rc = NSCD_CFG_SYNTAX_ERROR;
332 			return (rc);
333 		}
334 
335 		rc = _nscd_cfg_get_handle(pname, db, &h, errorp);
336 		if (rc != NSCD_SUCCESS) {
337 			/* ignore unsupported switch database */
338 			if (rc == NSCD_CFG_UNSUPPORTED_SWITCH_DB) {
339 				_nscd_cfg_free_error(*errorp);
340 				*errorp = NULL;
341 				rc = NSCD_SUCCESS;
342 				continue;
343 			}
344 			break;
345 		}
346 
347 		pdesc = _nscd_cfg_get_desc(h);
348 
349 		/* convert string to data */
350 		rc = _nscd_cfg_str_to_data(pdesc, nsscfg, &u.data,
351 			&data_p, errorp);
352 		if (rc != NSCD_SUCCESS)
353 			break;
354 
355 		/* do preliminary check based on data type */
356 		rc = _nscd_cfg_prelim_check(pdesc, data_p, errorp);
357 		if (rc != NSCD_SUCCESS)
358 			break;
359 
360 		rc = _nscd_cfg_set_linked(h, data_p, errorp);
361 		_nscd_cfg_free_handle(h);
362 		h = NULL;
363 		if (rc != NSCD_CFG_READ_ONLY && rc != NSCD_SUCCESS)
364 			break;
365 		else {
366 			_nscd_cfg_free_error(*errorp);
367 			*errorp = NULL;
368 		}
369 	}
370 	/* NSCD_CFG_READ_ONLY is not fatal */
371 	if (rc == NSCD_CFG_READ_ONLY)
372 		rc = NSCD_SUCCESS;
373 
374 	if (h != NULL)
375 		_nscd_cfg_free_handle(h);
376 
377 	(void) fclose(in);
378 
379 	if (msg[0] == '\0' && rc != NSCD_SUCCESS) {
380 		if (errorp != NULL)
381 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
382 			(me, "%s\n", NSCD_ERR2MSG(*errorp));
383 	}
384 
385 	return (rc);
386 }
387