xref: /illumos-gate/usr/src/cmd/nscd/nscd_cfgfile.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 #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] = strtok_r((i?(char *)NULL:s),
48 	    sep, &lasts)); i++) {
49 		/* empty */
50 	}
51 
52 	if (qp == NULL)
53 		return (i);
54 
55 	inquote = 1;
56 	while (++qp < lasts) {
57 
58 		switch (*qp) {
59 
60 		case '"':
61 			inquote = (inquote == 0);
62 			break;
63 
64 		case '\\':
65 			/* escape " */
66 			if (inquote == 1 && *(qp + 1) == '"')
67 				qp++;
68 			break;
69 
70 		case '\0':
71 			if (inquote == 1) {
72 				*qp = ' ';
73 				i--;
74 			}
75 
76 			break;
77 		}
78 	}
79 
80 	return (i);
81 }
82 
83 
84 nscd_rc_t
85 _nscd_cfg_read_file(
86 	char			*filename,
87 	nscd_cfg_error_t	**errorp)
88 {
89 	char			*me = "_nscd_cfg_read_file";
90 	FILE			*in;
91 	char			buffer[255];
92 	char			*fields [128];
93 	int			linecnt;
94 	int			fieldcnt;
95 	nscd_rc_t		rc = NSCD_SUCCESS;
96 	nscd_cfg_handle_t	*h = NULL;
97 	nscd_cfg_param_desc_t	*pdesc;
98 	char			*dbname, *str;
99 	void			*data_p;
100 	int			i;
101 	char			msg[NSCD_CFG_MAX_ERR_MSG_LEN];
102 
103 	union {
104 		int	i;
105 		char	data[256];
106 	} u;
107 
108 	if ((in = fopen(filename, "r")) == NULL) {
109 
110 		(void) snprintf(msg, sizeof (msg),
111 		    gettext("open of configuration file \"%s\" failed: %s"),
112 		    filename, strerror(errno));
113 		if (errorp != NULL)
114 			*errorp = _nscd_cfg_make_error(
115 			    NSCD_CFG_FILE_OPEN_ERROR, msg);
116 
117 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
118 		(me, "%s\n", msg);
119 
120 		return (NSCD_CFG_FILE_OPEN_ERROR);
121 	}
122 
123 	linecnt = 0;
124 	msg[0] = '\0';
125 	while (fgets(buffer, sizeof (buffer), in) != NULL) {
126 
127 		linecnt++;
128 		if ((fieldcnt = strbreak(fields, 128, buffer, " \t\n")) ==
129 		    0 || *fields[0] == '#') {
130 			/* skip blank or comment lines */
131 			continue;
132 		}
133 
134 		switch (fieldcnt) {
135 
136 		case 2:
137 			dbname = NULL;
138 			str = fields[1];
139 			break;
140 
141 		case 3:
142 			dbname = fields[1];
143 			str = fields[2];
144 			break;
145 
146 		default:
147 
148 			(void) strlcpy(u.data, fields[0], sizeof (u.data));
149 			for (i = 1; i < fieldcnt; i++) {
150 				(void) strlcat(u.data, " ",
151 				    sizeof (u.data));
152 				(void) strlcat(u.data, fields[i],
153 				    sizeof (u.data));
154 			}
155 
156 			(void) snprintf(msg, sizeof (msg),
157 		gettext("Syntax error: line %d of configuration "
158 			"file: %s : \"%s\""), linecnt, filename, u.data);
159 			if (errorp != NULL)
160 				*errorp = _nscd_cfg_make_error(
161 				    NSCD_CFG_SYNTAX_ERROR, msg);
162 
163 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
164 			(me, "%s\n", msg);
165 
166 			rc = NSCD_CFG_SYNTAX_ERROR;
167 			break;
168 		}
169 
170 		if (rc != NSCD_SUCCESS)
171 			break;
172 
173 		rc = _nscd_cfg_get_handle(fields[0], dbname, &h, errorp);
174 		if (rc != NSCD_SUCCESS)
175 			break;
176 
177 		pdesc = _nscd_cfg_get_desc(h);
178 
179 		/* convert string to data */
180 		rc = _nscd_cfg_str_to_data(pdesc, str, &u.data,
181 		    &data_p, errorp);
182 		if (rc != NSCD_SUCCESS)
183 			break;
184 
185 		/* do preliminary check based on data type */
186 		rc = _nscd_cfg_prelim_check(pdesc, data_p, errorp);
187 		if (rc != NSCD_SUCCESS)
188 			break;
189 
190 		rc = _nscd_cfg_set_linked(h, data_p, errorp);
191 		_nscd_cfg_free_handle(h);
192 		h = NULL;
193 		if (rc != NSCD_CFG_READ_ONLY && rc != NSCD_SUCCESS)
194 			break;
195 		else {
196 			_nscd_cfg_free_error(*errorp);
197 			*errorp = NULL;
198 		}
199 	}
200 	/* NSCD_CFG_READ_ONLY is not fatal */
201 	if (rc == NSCD_CFG_READ_ONLY)
202 		rc = NSCD_SUCCESS;
203 
204 	if (h != NULL)
205 		_nscd_cfg_free_handle(h);
206 
207 	(void) fclose(in);
208 
209 	if (msg[0] == '\0' && rc != NSCD_SUCCESS) {
210 		if (errorp != NULL)
211 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
212 			(me, "%s\n", NSCD_ERR2MSG(*errorp));
213 	}
214 
215 	return (rc);
216 }
217 
218 nscd_rc_t
219 _nscd_cfg_read_nsswitch_file(
220 	char			*filename,
221 	nscd_cfg_error_t	**errorp)
222 {
223 	char			*me = "_nscd_cfg_read_nsswitch_file";
224 	char			*pname = "nsw-config-string";
225 	FILE			*in;
226 	char			buffer[255];
227 	char			*cc, *ce, *ce1, *c1, *c2;
228 	char			*db, *dbe;
229 	char			*nsscfg;
230 	int			syntax_err;
231 	int			linecnt;
232 	nscd_rc_t		rc = NSCD_SUCCESS;
233 	nscd_cfg_handle_t	*h = NULL;
234 	nscd_cfg_param_desc_t	*pdesc;
235 	void			*data_p;
236 	char			msg[NSCD_CFG_MAX_ERR_MSG_LEN];
237 
238 	union {
239 		int	i;
240 		char	data[256];
241 	} u;
242 
243 	if ((in = fopen(filename, "r")) == NULL) {
244 
245 		(void) snprintf(msg, sizeof (msg),
246 		    gettext("open of configuration file \"%s\" failed: %s"),
247 		    filename, strerror(errno));
248 		if (errorp != NULL)
249 			*errorp = _nscd_cfg_make_error(
250 			    NSCD_CFG_FILE_OPEN_ERROR, msg);
251 
252 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
253 		(me, "%s\n", msg);
254 
255 		return (NSCD_CFG_FILE_OPEN_ERROR);
256 	}
257 
258 	linecnt = 0;
259 	msg[0] = '\0';
260 	while (fgets(buffer, sizeof (buffer), in) != NULL) {
261 
262 		linecnt++;
263 		syntax_err = 0;
264 		/* skip blank or comment lines */
265 		if (buffer[0] == '#' || buffer[0] == '\n')
266 			continue;
267 		/* skip end of line comment */
268 		if ((ce = strchr(buffer, '\n')) != NULL)
269 			*ce = '\0';
270 		else
271 			ce = &buffer[255];
272 		if ((ce1 = strchr(buffer, '#')) != NULL) {
273 			ce = ce1;
274 			*ce = '\0';
275 		}
276 		if ((cc = strchr(buffer, ':')) == NULL) {
277 			c1 = buffer;
278 			while (isalpha(*c1) && c1 < ce)
279 				c1++;
280 			if (c1 > ce)
281 				syntax_err = 1;
282 			else /* blank line */
283 				continue;
284 		} else {
285 			/*
286 			 * data name goes before ':',
287 			 * skip spaces on both ends
288 			 */
289 			c2 = cc - 1;
290 			while (buffer <= c2 && isspace(*c2))
291 				c2--;
292 			c1 = buffer;
293 			while (c1 <= cc && isspace(*c1))
294 				c1++;
295 			if (c1 > c2)
296 				syntax_err = 1;
297 			else {
298 				db = c1;
299 				dbe = c2 + 1;
300 
301 				/*
302 				 * nss config goes after ':',
303 				 * skip spaces on both ends
304 				 */
305 				c1 = cc + 1;
306 				while (c1 <= ce && isspace(*c1))
307 					c1++;
308 				c2 = ce - 1;
309 				while (cc <= c2 && isspace(*c2))
310 					c2--;
311 				if (c1 > c2) {
312 					/* no source specified, it's OK */
313 					continue;
314 				} else {
315 					*dbe = '\0';
316 					nsscfg = c1;
317 					*(c2 + 1) = '\0';
318 				}
319 			}
320 		}
321 
322 		if (syntax_err == 1) {
323 
324 			(void) snprintf(msg, sizeof (msg),
325 		gettext("Syntax error: line %d of configuration "
326 			"file: %s : \"%s\""), linecnt, filename, buffer);
327 			if (errorp != NULL)
328 				*errorp = _nscd_cfg_make_error(
329 				    NSCD_CFG_SYNTAX_ERROR, msg);
330 
331 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
332 			(me, "%s\n", msg);
333 
334 			rc = NSCD_CFG_SYNTAX_ERROR;
335 			return (rc);
336 		}
337 
338 		rc = _nscd_cfg_get_handle(pname, db, &h, errorp);
339 		if (rc != NSCD_SUCCESS) {
340 			/* ignore unsupported switch database */
341 			if (rc == NSCD_CFG_UNSUPPORTED_SWITCH_DB) {
342 				_nscd_cfg_free_error(*errorp);
343 				*errorp = NULL;
344 				rc = NSCD_SUCCESS;
345 				continue;
346 			}
347 			break;
348 		}
349 
350 		pdesc = _nscd_cfg_get_desc(h);
351 
352 		/* convert string to data */
353 		rc = _nscd_cfg_str_to_data(pdesc, nsscfg, &u.data,
354 		    &data_p, errorp);
355 		if (rc != NSCD_SUCCESS)
356 			break;
357 
358 		/* do preliminary check based on data type */
359 		rc = _nscd_cfg_prelim_check(pdesc, data_p, errorp);
360 		if (rc != NSCD_SUCCESS)
361 			break;
362 
363 		rc = _nscd_cfg_set_linked(h, data_p, errorp);
364 		_nscd_cfg_free_handle(h);
365 		h = NULL;
366 		if (rc != NSCD_CFG_READ_ONLY && rc != NSCD_SUCCESS)
367 			break;
368 		else {
369 			_nscd_cfg_free_error(*errorp);
370 			*errorp = NULL;
371 		}
372 	}
373 	/* NSCD_CFG_READ_ONLY is not fatal */
374 	if (rc == NSCD_CFG_READ_ONLY)
375 		rc = NSCD_SUCCESS;
376 
377 	if (h != NULL)
378 		_nscd_cfg_free_handle(h);
379 
380 	(void) fclose(in);
381 
382 	if (msg[0] == '\0' && rc != NSCD_SUCCESS) {
383 		if (errorp != NULL)
384 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
385 			(me, "%s\n", NSCD_ERR2MSG(*errorp));
386 	}
387 
388 	return (rc);
389 }
390