xref: /illumos-gate/usr/src/cmd/nscd/nscd_cfgfile.c (revision f17620a4f72a29025a22655ba8735ccd20ae174f)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  *   routine to read configuration file
28  *
29  */
30 #include "nscd_config.h"
31 #include "nscd_log.h"
32 #include <locale.h>
33 #include <ctype.h>
34 #include <string.h>
35 #include <errno.h>
36 
37 static int
38 strbreak(char *field[], int array_size, char *s, char *sep)
39 {
40 	int	i;
41 	char	*lasts, *qp;
42 	int	inquote;
43 
44 	qp = strchr(s, '"');
45 	for (i = 0; i < array_size && (field[i] = strtok_r((i?(char *)NULL:s),
46 	    sep, &lasts)); i++) {
47 		/* empty */
48 	}
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 					/* no source specified, it's OK */
311 					continue;
312 				} else {
313 					*dbe = '\0';
314 					nsscfg = c1;
315 					*(c2 + 1) = '\0';
316 				}
317 			}
318 		}
319 
320 		if (syntax_err == 1) {
321 
322 			(void) snprintf(msg, sizeof (msg),
323 		gettext("Syntax error: line %d of configuration "
324 			"file: %s : \"%s\""), linecnt, filename, buffer);
325 			if (errorp != NULL)
326 				*errorp = _nscd_cfg_make_error(
327 				    NSCD_CFG_SYNTAX_ERROR, msg);
328 
329 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
330 			(me, "%s\n", msg);
331 
332 			rc = NSCD_CFG_SYNTAX_ERROR;
333 			return (rc);
334 		}
335 
336 		rc = _nscd_cfg_get_handle(pname, db, &h, errorp);
337 		if (rc != NSCD_SUCCESS) {
338 			/* ignore unsupported switch database */
339 			if (rc == NSCD_CFG_UNSUPPORTED_SWITCH_DB) {
340 				_nscd_cfg_free_error(*errorp);
341 				*errorp = NULL;
342 				rc = NSCD_SUCCESS;
343 				continue;
344 			}
345 			break;
346 		}
347 
348 		pdesc = _nscd_cfg_get_desc(h);
349 
350 		/* convert string to data */
351 		rc = _nscd_cfg_str_to_data(pdesc, nsscfg, &u.data,
352 		    &data_p, errorp);
353 		if (rc != NSCD_SUCCESS)
354 			break;
355 
356 		/* do preliminary check based on data type */
357 		rc = _nscd_cfg_prelim_check(pdesc, data_p, errorp);
358 		if (rc != NSCD_SUCCESS)
359 			break;
360 
361 		rc = _nscd_cfg_set_linked(h, data_p, errorp);
362 		_nscd_cfg_free_handle(h);
363 		h = NULL;
364 		if (rc != NSCD_CFG_READ_ONLY && rc != NSCD_SUCCESS)
365 			break;
366 		else {
367 			_nscd_cfg_free_error(*errorp);
368 			*errorp = NULL;
369 		}
370 	}
371 	/* NSCD_CFG_READ_ONLY is not fatal */
372 	if (rc == NSCD_CFG_READ_ONLY)
373 		rc = NSCD_SUCCESS;
374 
375 	if (h != NULL)
376 		_nscd_cfg_free_handle(h);
377 
378 	(void) fclose(in);
379 
380 	if (msg[0] == '\0' && rc != NSCD_SUCCESS) {
381 		if (errorp != NULL)
382 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
383 			(me, "%s\n", NSCD_ERR2MSG(*errorp));
384 	}
385 
386 	return (rc);
387 }
388