xref: /illumos-gate/usr/src/lib/libnisdb/nis_parse_ldap_attr.c (revision 1da57d551424de5a9d469760be7c4b4d4f10a755)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <ctype.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <errno.h>
34 #include <locale.h>
35 #include <lber.h>
36 #include <ldap.h>
37 #include <syslog.h>
38 
39 #include "ldap_parse.h"
40 #include "nis_parse_ldap_conf.h"
41 
42 extern FILE *cons;
43 
44 static bool_t get_timeval_t(const char *s, int len, struct timeval *t,
45 	time_t default_val);
46 static bool_t get_limit(const char *s, int len, int *limit, int default_val);
47 static bool_t get_time_t(const char *s, time_t *t, time_t default_val);
48 static bool_t get_uint_val(const char *attrib_val, int *val, int default_val);
49 static bool_t get_int_val(const char *attrib_val, int *val, int default_val);
50 static void warn_duplicate_val(config_key attrib_num);
51 
52 static struct {
53 	const char	*key_name;
54 	config_key	key_id;
55 } keyword_lookup[] = {
56 	{CONFIG_DN,		key_config_dn},
57 	{YP_CONFIG_DN,	key_yp_config_dn},
58 	{CONFIG_SERVER_LIST,	key_config_server_list},
59 	{YP_CONFIG_SERVER_LIST,	key_yp_config_server_list},
60 	{CONFIG_AUTH_METHOD,	key_config_auth_method},
61 	{YP_CONFIG_AUTH_METHOD,	key_yp_config_auth_method},
62 	{CONFIG_TLS_OPTION,		key_config_tls_option},
63 	{YP_CONFIG_TLS_OPTION,	key_yp_config_tls_option},
64 	{CONFIG_TLS_CERT_DB,	key_config_tls_certificate_db},
65 	{YP_CONFIG_TLS_CERT_DB,	key_yp_config_tls_certificate_db},
66 	{CONFIG_PROXY_USER,		key_config_proxy_user},
67 	{YP_CONFIG_PROXY_USER,	key_yp_config_proxy_user},
68 	{CONFIG_PROXY_PASSWD,	key_config_proxy_passwd},
69 	{YP_CONFIG_PROXY_PASSWD,	key_yp_config_proxy_passwd},
70 	{PREFERRED_SERVERS,		key_preferred_servers},
71 	{AUTH_METHOD,		key_auth_method},
72 	{TLS_OPTION,		key_tls_option},
73 	{YP_TLS_OPTION,		key_yp_tls_option},
74 	{TLS_CERT_DB,		key_tls_certificate_db},
75 	{YP_TLS_CERT_DB,	key_yp_tls_certificate_db},
76 	{SEARCH_BASE,		key_search_base},
77 	{PROXY_USER,		key_proxy_user},
78 	{YP_PROXY_USER,		key_yp_proxy_user},
79 	{PROXY_PASSWD,		key_proxy_passwd},
80 	{YP_PROXY_PASSWD,	key_yp_proxy_passwd},
81 	{LDAP_BASE_DOMAIN,	key_ldap_base_domain},
82 	{YP_LDAP_BASE_DOMAIN,	key_yp_ldap_base_domain},
83 	{BIND_TIMEOUT,		key_bind_timeout},
84 	{YP_BIND_TIMEOUT,	key_yp_bind_timeout},
85 	{SEARCH_TIMEOUT,	key_search_timeout},
86 	{YP_SEARCH_TIMEOUT,	key_yp_search_timeout},
87 	{MODIFY_TIMEOUT,	key_modify_timeout},
88 	{YP_MODIFY_TIMEOUT,	key_yp_modify_timeout},
89 	{ADD_TIMEOUT,		key_add_timeout},
90 	{YP_ADD_TIMEOUT,	key_yp_add_timeout},
91 
92 	{DELETE_TIMEOUT,	key_delete_timeout},
93 	{YP_DELETE_TIMEOUT,	key_yp_delete_timeout},
94 	{SEARCH_TIME_LIMIT,	key_search_time_limit},
95 	{YP_SEARCH_TIME_LIMIT,	key_yp_search_time_limit},
96 	{SEARCH_SIZE_LIMIT,	key_search_size_limit},
97 	{YP_SEARCH_SIZE_LIMIT,	key_yp_search_size_limit},
98 	{FOLLOW_REFERRAL,	key_follow_referral},
99 	{YP_FOLLOW_REFERRAL,	key_yp_follow_referral},
100 	{INITIAL_UPDATE_ACTION,	key_initial_update_action},
101 	{INITIAL_UPDATE_ONLY,	key_initial_update_only},
102 	{RETRIEVE_ERROR_ACTION,	key_retrieve_error_action},
103 	{YP_RETRIEVE_ERROR_ACTION,	key_yp_retrieve_error_action},
104 	{RETREIVE_ERROR_ATTEMPTS,
105 				key_retrieve_error_attempts},
106 	{YP_RETREIVE_ERROR_ATTEMPTS,
107 				key_yp_retrieve_error_attempts},
108 	{RETREIVE_ERROR_TIMEOUT,
109 				key_retreive_error_timeout},
110 	{YP_RETREIVE_ERROR_TIMEOUT,
111 				key_yp_retreive_error_timeout},
112 	{STORE_ERROR_ACTION,	key_store_error_action},
113 	{YP_STORE_ERROR_ACTION,	key_yp_store_error_action},
114 	{STORE_ERROR_ATTEMPTS,	key_store_error_attempts},
115 	{YP_STORE_ERROR_ATTEMPTS,	key_yp_store_error_attempts},
116 	{STORE_ERROR_TIMEOUT,	key_store_error_timeout},
117 	{YP_STORE_ERROR_TIMEOUT,	key_yp_store_error_timeout},
118 
119 	{REFRESH_ERROR_ACTION,	key_refresh_error_action},
120 
121 	{REFRESH_ERROR_ATTEMPTS,
122 				key_refresh_error_attempts},
123 	{REFRESH_ERROR_TIMEOUT,	key_refresh_error_timeout},
124 	{THREAD_CREATE_ERROR_ACTION,
125 				key_thread_create_error_action},
126 	{THREAD_CREATE_ERROR_ATTEMPTS,
127 				key_thread_create_error_attempts},
128 	{THREAD_CREATE_ERROR_TIMEOUT,
129 				key_thread_create_error_timeout},
130 	{DUMP_ERROR_ACTION,	key_dump_error_action},
131 	{DUMP_ERROR_ATTEMPTS,	key_dump_error_attempts},
132 	{DUMP_ERROR_TIMEOUT,	key_dump_error_timeout},
133 	{RESYNC,		key_resync},
134 	{UPDATE_BATCHING,	key_update_batching},
135 	{UPDATE_BATCHING_TIMEOUT,
136 				key_update_batching_timeout},
137 	{MATCH_FETCH,		key_match_fetch},
138 	{YP_MATCH_FETCH,	key_yp_match_fetch},
139 	{NUMBER_THEADS,		key_number_threads},
140 	{YP_EMULATION,		key_yp_emulation},
141 	{MAX_RPC_RECSIZE,	key_max_rpc_recsize},
142 	{YP_DOMAIN_CONTEXT,	key_yp_domain_context},
143 	{YPPASSWDD_DOMAINS,	key_yppasswdd_domains},
144 	{DB_ID_MAP,		key_db_id_map},
145 	{YP_DB_ID_MAP,	key_yp_db_id_map},
146 	{YP_COMMENT_CHAR,	key_yp_comment_char},
147 	{YP_MAP_FLAGS,		key_yp_map_flags},
148 	{ENTRY_TTL,		key_entry_ttl},
149 	{YP_ENTRY_TTL,	key_yp_entry_ttl},
150 	{YP_NAME_FIELDS,	key_yp_name_fields},
151 	{YP_SPLIT_FIELD,	key_yp_split_field},
152 	{YP_REPEATED_FIELD_SEPARATORS,	key_yp_repeated_field_separators},
153 	{LDAP_OBJECT_DN,	key_ldap_object_dn},
154 	{YP_LDAP_OBJECT_DN,	key_yp_ldap_object_dn},
155 	{LDAP_TO_NISPLUS_MAP,	key_ldap_to_nisplus_map},
156 	{LDAP_TO_NIS_MAP,	key_ldap_to_nis_map},
157 	{NISPLUS_TO_LDAP_MAP,	key_nisplus_to_ldap_map},
158 	{NIS_TO_LDAP_MAP,	key_nis_to_ldap_map}
159 };
160 
161 /*
162  * FUNCTION:	add_config_attribute
163  *
164  *	Adds the attribute value to __nis_config_info_t
165  *	if the value is not yet set.
166  *
167  * RETURN VALUE:	0 on success, -1 on failure
168  *
169  * INPUT:		attribute number and value (assumed to be non-NULL)
170  */
171 
172 int
add_config_attribute(config_key attrib_num,const char * attrib_val,int attrib_len,__nis_config_info_t * config_info)173 add_config_attribute(
174 	config_key		attrib_num,
175 	const char		*attrib_val,
176 	int			attrib_len,
177 	__nis_config_info_t	*config_info)
178 {
179 	switch (attrib_num) {
180 		case key_yp_config_dn:
181 		case key_config_dn:
182 			if (config_info->config_dn == NULL) {
183 				if (!validate_dn(attrib_val, attrib_len))
184 					break;
185 				config_info->config_dn =
186 					s_strndup(attrib_val, attrib_len);
187 			} else {
188 				warn_duplicate_val(attrib_num);
189 			}
190 			break;
191 		case key_yp_config_server_list:
192 		case key_config_server_list:
193 			if (config_info->default_servers == NULL) {
194 				config_info->default_servers =
195 					s_strndup(attrib_val, attrib_len);
196 			} else {
197 				warn_duplicate_val(attrib_num);
198 			}
199 			break;
200 		case key_yp_config_auth_method:
201 		case key_config_auth_method:
202 			if (config_info->auth_method ==
203 			    (auth_method_t)NO_VALUE_SET) {
204 				if (same_string("none", attrib_val,
205 						attrib_len))
206 					config_info->auth_method = none;
207 				else if (same_string("simple", attrib_val,
208 						attrib_len))
209 					config_info->auth_method = simple;
210 				else if (same_string("sasl/cram-md5",
211 						attrib_val, attrib_len))
212 					config_info->auth_method = cram_md5;
213 				else if (same_string("sasl/digest-md5",
214 						attrib_val, attrib_len))
215 					config_info->auth_method = digest_md5;
216 				else
217 					p_error = parse_bad_auth_method_error;
218 			} else {
219 				warn_duplicate_val(attrib_num);
220 			}
221 			break;
222 		case key_yp_config_tls_option:
223 		case key_config_tls_option:
224 			if (config_info->tls_method ==
225 			    (tls_method_t)NO_VALUE_SET) {
226 				if (same_string("none", attrib_val,
227 						attrib_len))
228 					config_info->tls_method = no_tls;
229 				else if (same_string("ssl", attrib_val,
230 						attrib_len))
231 					config_info->tls_method = ssl_tls;
232 				else
233 					p_error = parse_bad_tls_option_error;
234 			} else {
235 				warn_duplicate_val(attrib_num);
236 			}
237 			break;
238 		case key_yp_config_tls_certificate_db:
239 		case key_config_tls_certificate_db:
240 			if (config_info->tls_cert_db == NULL) {
241 				config_info->tls_cert_db =
242 					s_strndup(attrib_val, attrib_len);
243 			} else {
244 				warn_duplicate_val(attrib_num);
245 			}
246 			break;
247 		case key_yp_config_proxy_user:
248 		case key_config_proxy_user:
249 			if (config_info->proxy_dn == NULL) {
250 				config_info->proxy_dn =
251 					s_strndup(attrib_val, attrib_len);
252 			} else {
253 				warn_duplicate_val(attrib_num);
254 			}
255 			break;
256 		case key_yp_config_proxy_passwd:
257 		case key_config_proxy_passwd:
258 			if (config_info->proxy_passwd == NULL) {
259 				config_info->proxy_passwd =
260 					s_strndup_esc(attrib_val, attrib_len);
261 			} else {
262 				warn_duplicate_val(attrib_num);
263 			}
264 			break;
265 		default:
266 			p_error = parse_internal_error;
267 			break;
268 	}
269 	return (p_error == no_parse_error ? 0 : -1);
270 }
271 
272 /*
273  * FUNCTION:	add_bind_attribute
274  *
275  *	Adds the attribute value to __nis_ldap_proxy_info
276  *	if the value is not yet set.
277  *
278  * RETURN VALUE:	0 on success, -1 on failure
279  *
280  * INPUT:		attribute number and value (assumed to be non-NULL)
281  */
282 
283 int
add_bind_attribute(config_key attrib_num,const char * attrib_val,int attrib_len,__nis_ldap_proxy_info * proxy_info)284 add_bind_attribute(
285 	config_key		attrib_num,
286 	const char		*attrib_val,
287 	int			attrib_len,
288 	__nis_ldap_proxy_info	*proxy_info)
289 {
290 	struct timeval	t;
291 	int		limit;
292 
293 	switch (attrib_num) {
294 		case key_yp_preferred_servers:
295 		case key_preferred_servers:
296 			if (proxy_info->default_servers == NULL) {
297 				proxy_info->default_servers =
298 					s_strndup(attrib_val, attrib_len);
299 			} else {
300 				warn_duplicate_val(attrib_num);
301 			}
302 			break;
303 		case key_yp_auth_method:
304 		case key_auth_method:
305 			if (proxy_info->auth_method ==
306 			    (auth_method_t)NO_VALUE_SET) {
307 				if (same_string("none", attrib_val,
308 						attrib_len))
309 					proxy_info->auth_method = none;
310 				else if (same_string("simple", attrib_val,
311 						attrib_len))
312 					proxy_info->auth_method = simple;
313 				else if (same_string("sasl/cram-md5",
314 						attrib_val, attrib_len))
315 					proxy_info->auth_method = cram_md5;
316 				else if (same_string("sasl/digest-md5",
317 						attrib_val, attrib_len))
318 					proxy_info->auth_method = digest_md5;
319 				else
320 					p_error = parse_bad_auth_method_error;
321 			} else {
322 				warn_duplicate_val(attrib_num);
323 			}
324 			break;
325 		case key_yp_tls_option:
326 		case key_tls_option:
327 			if (proxy_info->tls_method ==
328 			    (tls_method_t)NO_VALUE_SET) {
329 				if (same_string("none", attrib_val,
330 						attrib_len))
331 					proxy_info->tls_method = no_tls;
332 				else if (same_string("ssl", attrib_val,
333 						attrib_len))
334 					proxy_info->tls_method = ssl_tls;
335 				else
336 					p_error = parse_bad_tls_option_error;
337 			} else {
338 				warn_duplicate_val(attrib_num);
339 			}
340 			break;
341 		case key_yp_tls_certificate_db:
342 		case key_tls_certificate_db:
343 			if (proxy_info->tls_cert_db == NULL) {
344 				proxy_info->tls_cert_db =
345 					s_strndup(attrib_val, attrib_len);
346 			} else {
347 				warn_duplicate_val(attrib_num);
348 			}
349 			break;
350 		case key_yp_search_base:
351 		case key_search_base:
352 			if (proxy_info->default_search_base == NULL) {
353 				if (!validate_dn(attrib_val, attrib_len))
354 					break;
355 				proxy_info->default_search_base =
356 					s_strndup(attrib_val, attrib_len);
357 			} else {
358 				warn_duplicate_val(attrib_num);
359 			}
360 			break;
361 		case key_yp_proxy_user:
362 		case key_proxy_user:
363 			if (proxy_info->proxy_dn == NULL) {
364 				proxy_info->proxy_dn =
365 					s_strndup(attrib_val, attrib_len);
366 			} else {
367 				warn_duplicate_val(attrib_num);
368 			}
369 			break;
370 		case key_yp_proxy_passwd:
371 		case key_proxy_passwd:
372 			if (proxy_info->proxy_passwd == NULL) {
373 				proxy_info->proxy_passwd =
374 					s_strndup_esc(attrib_val, attrib_len);
375 			} else {
376 				warn_duplicate_val(attrib_num);
377 			}
378 			break;
379 		case key_yp_ldap_base_domain:
380 		case key_ldap_base_domain:
381 			if (proxy_info->default_nis_domain == NULL) {
382 				proxy_info->default_nis_domain =
383 					s_strndup_esc(attrib_val, attrib_len);
384 			} else {
385 				warn_duplicate_val(attrib_num);
386 			}
387 			break;
388 		case key_yp_bind_timeout:
389 		case key_bind_timeout:
390 			if (proxy_info->bind_timeout.tv_sec ==
391 			    (time_t)NO_VALUE_SET) {
392 				if (!get_timeval_t(attrib_val, attrib_len, &t,
393 						DEFAULT_BIND_TIMEOUT))
394 					break;
395 				proxy_info->bind_timeout = t;
396 			} else {
397 				warn_duplicate_val(attrib_num);
398 			}
399 			break;
400 		case key_yp_search_timeout:
401 			if (proxy_info->search_timeout.tv_sec ==
402 			    (time_t)NO_VALUE_SET) {
403 				if (!get_timeval_t(attrib_val, attrib_len, &t,
404 						DEFAULT_YP_SEARCH_TIMEOUT))
405 					break;
406 				proxy_info->search_timeout = t;
407 			} else {
408 				warn_duplicate_val(attrib_num);
409 			}
410 			break;
411 
412 		case key_search_timeout:
413 			if (proxy_info->search_timeout.tv_sec ==
414 			    (time_t)NO_VALUE_SET) {
415 				if (!get_timeval_t(attrib_val, attrib_len, &t,
416 						DEFAULT_SEARCH_TIMEOUT))
417 					break;
418 				proxy_info->search_timeout = t;
419 			} else {
420 				warn_duplicate_val(attrib_num);
421 			}
422 			break;
423 		case key_yp_modify_timeout:
424 		case key_modify_timeout:
425 			if (proxy_info->modify_timeout.tv_sec ==
426 			    (time_t)NO_VALUE_SET) {
427 				if (!get_timeval_t(attrib_val, attrib_len, &t,
428 						DEFAULT_MODIFY_TIMEOUT))
429 					break;
430 				proxy_info->modify_timeout = t;
431 			} else {
432 				warn_duplicate_val(attrib_num);
433 			}
434 			break;
435 		case key_yp_add_timeout:
436 		case key_add_timeout:
437 			if (proxy_info->add_timeout.tv_sec ==
438 			    (time_t)NO_VALUE_SET) {
439 				if (!get_timeval_t(attrib_val, attrib_len, &t,
440 						DEFAULT_ADD_TIMEOUT))
441 					break;
442 				proxy_info->add_timeout = t;
443 			} else {
444 				warn_duplicate_val(attrib_num);
445 			}
446 			break;
447 		case key_yp_delete_timeout:
448 		case key_delete_timeout:
449 			if (proxy_info->delete_timeout.tv_sec ==
450 			    (time_t)NO_VALUE_SET) {
451 				if (!get_timeval_t(attrib_val, attrib_len, &t,
452 						DEFAULT_DELETE_TIMEOUT))
453 					break;
454 				proxy_info->delete_timeout = t;
455 			} else {
456 				warn_duplicate_val(attrib_num);
457 			}
458 			break;
459 		case key_yp_search_time_limit:
460 		case key_search_time_limit:
461 			if (proxy_info->search_time_limit ==
462 			    (int)NO_VALUE_SET) {
463 				if (!get_limit(attrib_val, attrib_len, &limit,
464 						DEFAULT_SEARCH_TIME_LIMIT))
465 					break;
466 				proxy_info->search_time_limit = limit;
467 			} else {
468 				warn_duplicate_val(attrib_num);
469 			}
470 			break;
471 		case key_yp_search_size_limit:
472 		case key_search_size_limit:
473 			if (proxy_info->search_size_limit ==
474 			    (int)NO_VALUE_SET) {
475 				if (!get_limit(attrib_val, attrib_len, &limit,
476 						DEFAULT_SEARCH_SIZE_LIMIT))
477 					break;
478 				proxy_info->search_size_limit = limit;
479 			} else {
480 				warn_duplicate_val(attrib_num);
481 			}
482 			break;
483 		case key_yp_follow_referral:
484 		case key_follow_referral:
485 			if (proxy_info->follow_referral ==
486 					(follow_referral_t)NO_VALUE_SET) {
487 			    if (same_string("yes", attrib_val, attrib_len))
488 				proxy_info->follow_referral = follow;
489 			    else if (same_string("no", attrib_val, attrib_len))
490 				proxy_info->follow_referral = no_follow;
491 			    else
492 				p_error = parse_yes_or_no_expected_error;
493 			} else {
494 				warn_duplicate_val(attrib_num);
495 			}
496 			break;
497 		default:
498 			p_error = parse_internal_error;
499 			break;
500 	}
501 	return (p_error == no_parse_error ? 0 : -1);
502 }
503 
504 /*
505  * FUNCTION:	add_operation_attribute
506  *
507  *	Adds the attribute value to __nis_config_t and
508  *	__nisdb_table_mapping_t if the value is not yet set.
509  *
510  * RETURN VALUE:	0 on success, -1 on failure
511  *
512  * INPUT:		attribute number and value (assumed to be non-NULL)
513  */
514 
515 int
add_operation_attribute(config_key attrib_num,const char * attrib_val,int attrib_len,__nis_config_t * config_info,__nisdb_table_mapping_t * table_info)516 add_operation_attribute(
517 	config_key		attrib_num,
518 	const char		*attrib_val,
519 	int			attrib_len,
520 	__nis_config_t		*config_info,
521 	__nisdb_table_mapping_t	*table_info)
522 {
523 	char	buf[1024];
524 	int	i;
525 	int	len;
526 	time_t	timeout;
527 	bool_t	last_digit = FALSE;
528 
529 	for (i = 0, len = 0; i < attrib_len; i++) {
530 		if (!last_digit &&
531 			is_whitespace(attrib_val[i]))
532 				continue;
533 		buf[len++] = attrib_val[i];
534 		if (len >= sizeof (buf)) {
535 			p_error = parse_line_too_long;
536 			return (-1);
537 		}
538 		last_digit = isdigit(attrib_val[i]);
539 	}
540 	buf[len] = '\0';
541 
542 	switch (attrib_num) {
543 	    case key_initial_update_action:
544 		if (config_info->initialUpdate ==
545 			(__nis_initial_update_t)NO_VALUE_SET) {
546 		    if (strcasecmp("none", buf) == 0)
547 			    config_info->initialUpdate = ini_none;
548 		    else if (strcasecmp("from_ldap", buf) == 0)
549 			    config_info->initialUpdate =
550 				(__nis_initial_update_t)FROM_NO_INITIAL_UPDATE;
551 		    else if (strcasecmp("to_ldap", buf) == 0)
552 			    config_info->initialUpdate =
553 				(__nis_initial_update_t)TO_NO_INITIAL_UPDATE;
554 		    else
555 			p_error = parse_initial_update_action_error;
556 		} else if (config_info->initialUpdate ==
557 			(__nis_initial_update_t)INITIAL_UPDATE_NO_ACTION) {
558 		    if (strcasecmp("none", buf) == 0)
559 			    config_info->initialUpdate = ini_none;
560 		    else if (strcasecmp("from_ldap", buf) == 0)
561 			    config_info->initialUpdate = from_ldap_update_only;
562 		    else if (strcasecmp("to_ldap", buf) == 0)
563 			    config_info->initialUpdate = to_ldap_update_only;
564 		    else
565 			p_error = parse_initial_update_action_error;
566 		} else if (config_info->initialUpdate ==
567 			(__nis_initial_update_t)NO_INITIAL_UPDATE_NO_ACTION) {
568 		    if (strcasecmp("none", buf) == 0)
569 			    config_info->initialUpdate = ini_none;
570 		    else if (strcasecmp("from_ldap", buf) == 0)
571 			    config_info->initialUpdate = from_ldap;
572 		    else if (strcasecmp("to_ldap", buf) == 0)
573 			    config_info->initialUpdate = to_ldap;
574 		    else
575 			p_error = parse_initial_update_action_error;
576 		} else {
577 		    warn_duplicate_val(attrib_num);
578 		}
579 		break;
580 	    case key_initial_update_only:
581 		if (config_info->initialUpdate ==
582 			(__nis_initial_update_t)NO_VALUE_SET) {
583 		    if (strcasecmp("yes", buf) == 0)
584 			    config_info->initialUpdate =
585 				(__nis_initial_update_t)
586 					INITIAL_UPDATE_NO_ACTION;
587 		    else if (strcasecmp("no", buf) == 0)
588 			    config_info->initialUpdate =
589 				(__nis_initial_update_t)
590 					NO_INITIAL_UPDATE_NO_ACTION;
591 		    else
592 			p_error = parse_initial_update_only_error;
593 		} else if (config_info->initialUpdate ==
594 			(__nis_initial_update_t)FROM_NO_INITIAL_UPDATE) {
595 		    if (strcasecmp("yes", buf) == 0)
596 			    config_info->initialUpdate = from_ldap_update_only;
597 		    else if (strcasecmp("no", buf) == 0)
598 			    config_info->initialUpdate = from_ldap;
599 		    else
600 			p_error = parse_initial_update_only_error;
601 		} else if (config_info->initialUpdate ==
602 			(__nis_initial_update_t)TO_NO_INITIAL_UPDATE) {
603 		    if (strcasecmp("yes", buf) == 0)
604 			    config_info->initialUpdate = to_ldap_update_only;
605 		    else if (strcasecmp("no", buf) == 0)
606 			    config_info->initialUpdate = to_ldap;
607 		    else
608 			p_error = parse_initial_update_only_error;
609 		} else if (config_info->initialUpdate != ini_none) {
610 		    warn_duplicate_val(attrib_num);
611 		}
612 		break;
613 	    case key_thread_create_error_action:
614 		if (config_info->threadCreationError ==
615 			(__nis_thread_creation_error_t)NO_VALUE_SET) {
616 		    if (strcasecmp("pass_error", buf) == 0)
617 			    config_info->threadCreationError = pass_error;
618 		    else if (strcasecmp("retry", buf) == 0)
619 			    config_info->threadCreationError = cre_retry;
620 		    else
621 			p_error = parse_thread_create_error_action_error;
622 		} else {
623 		    warn_duplicate_val(attrib_num);
624 		}
625 		break;
626 	    case key_thread_create_error_attempts:
627 		if (config_info->threadCreationErrorTimeout.attempts ==
628 			NO_VALUE_SET) {
629 		    if (get_int_val(buf, &i, DEFAULT_THREAD_ERROR_ATTEMPTS))
630 			config_info->threadCreationErrorTimeout.attempts = i;
631 		} else {
632 		    warn_duplicate_val(attrib_num);
633 		}
634 		break;
635 	    case key_thread_create_error_timeout:
636 		if (config_info->threadCreationErrorTimeout.timeout ==
637 			(time_t)NO_VALUE_SET) {
638 		    if (get_time_t(buf, &timeout,
639 				DEFAULT_THREAD_ERROR_TIME_OUT))
640 			config_info->threadCreationErrorTimeout.timeout =
641 				timeout;
642 		} else {
643 		    warn_duplicate_val(attrib_num);
644 		}
645 		break;
646 	    case key_dump_error_action:
647 		if (config_info->dumpError ==
648 			(__nis_dump_error_t)NO_VALUE_SET) {
649 		    if (strcasecmp("rollback", buf) == 0)
650 			    config_info->dumpError = rollback;
651 		    else if (strcasecmp("retry", buf) == 0)
652 			    config_info->dumpError = de_retry;
653 		    else
654 			p_error = parse_dump_error_action_error;
655 		} else {
656 		    warn_duplicate_val(attrib_num);
657 		}
658 		break;
659 	    case key_dump_error_attempts:
660 		if (config_info->dumpErrorTimeout.attempts == NO_VALUE_SET) {
661 		    if (get_int_val(buf, &i, DEFAULT_DUMP_ERROR_ATTEMPTS))
662 			config_info->dumpErrorTimeout.attempts = i;
663 		} else {
664 		    warn_duplicate_val(attrib_num);
665 		}
666 		break;
667 	    case key_dump_error_timeout:
668 		if (config_info->dumpErrorTimeout.timeout ==
669 			(time_t)NO_VALUE_SET) {
670 		    if (get_time_t(buf, &timeout,
671 				DEFAULT_DUMP_ERROR_TIME_OUT))
672 			config_info->dumpErrorTimeout.timeout = timeout;
673 		} else {
674 		    warn_duplicate_val(attrib_num);
675 		}
676 		break;
677 	    case key_resync:
678 		if (config_info->resyncService ==
679 			(__nis_resync_service_t)NO_VALUE_SET) {
680 		    if (strcasecmp("directory_locked", buf) == 0)
681 			    config_info->resyncService = directory_locked;
682 		    else if (strcasecmp("from_copy", buf) == 0)
683 			    config_info->resyncService = from_copy;
684 		    else if (strcasecmp("from_live", buf) == 0)
685 			    config_info->resyncService = from_live;
686 		    else
687 			p_error = parse_resync_error;
688 		} else {
689 		    warn_duplicate_val(attrib_num);
690 		}
691 		break;
692 	    case key_update_batching:
693 		if (config_info->updateBatching ==
694 			(__nis_update_batching_t)NO_VALUE_SET) {
695 		    if (strcasecmp("none", buf) == 0)
696 			    config_info->updateBatching = upd_none;
697 		    else if (strcasecmp("accumulate", buf) == 0) {
698 			    config_info->updateBatching = accumulate;
699 		    } else if (strcasecmp("bounded_accumulate", buf) == 0) {
700 			    config_info->updateBatching = bounded_accumulate;
701 		    } else
702 			p_error = parse_update_batching_error;
703 		} else {
704 		    warn_duplicate_val(attrib_num);
705 		}
706 		break;
707 	    case key_update_batching_timeout:
708 		if (config_info->updateBatchingTimeout.timeout ==
709 			(time_t)NO_VALUE_SET) {
710 		    if (get_time_t(buf, &timeout, DEFAULT_BATCHING_TIME_OUT))
711 			config_info->updateBatchingTimeout.timeout = timeout;
712 		} else {
713 		    warn_duplicate_val(attrib_num);
714 		}
715 		break;
716 	    case key_number_threads:
717 		if (config_info->numberOfServiceThreads ==
718 			(int)NO_VALUE_SET) {
719 		    if (get_uint_val(buf, &i, DEFAULT_NUMBER_OF_THREADS))
720 			    config_info->numberOfServiceThreads = i;
721 		} else {
722 		    warn_duplicate_val(attrib_num);
723 		}
724 		break;
725 	    case key_yp_emulation:
726 		if (config_info->emulate_yp ==
727 			(int)NO_VALUE_SET) {
728 		    if (strcasecmp("yes", buf) == 0)
729 			    config_info->emulate_yp = TRUE;
730 		} else {
731 		    warn_duplicate_val(attrib_num);
732 		}
733 		break;
734 		case key_yp_retrieve_error_action:
735 		if (table_info->retrieveError ==
736 			(__nis_retrieve_error_t)NO_VALUE_SET) {
737 			if (strcasecmp("use_cached", buf) == 0)
738 				table_info->retrieveError = use_cached;
739 			else if (strcasecmp("fail", buf) == 0)
740 				table_info->retrieveError = fail;
741 			else
742 		p_error = parse_yp_retrieve_error_action_error;
743 		} else {
744 			warn_duplicate_val(attrib_num);
745 		}
746 		break;
747 	    case key_retrieve_error_action:
748 		if (table_info->retrieveError ==
749 			(__nis_retrieve_error_t)NO_VALUE_SET) {
750 		    if (strcasecmp("use_cached", buf) == 0)
751 			    table_info->retrieveError = use_cached;
752 		    else if (strcasecmp("try_again", buf) == 0)
753 			    table_info->retrieveError = try_again;
754 		    else if (strcasecmp("unavail", buf) == 0)
755 			    table_info->retrieveError = ret_unavail;
756 		    else if (strcasecmp("no_such_name", buf) == 0)
757 			    table_info->retrieveError = no_such_name;
758 		    else if (strcasecmp("retry", buf) == 0)
759 			    table_info->retrieveError = ret_retry;
760 		    else
761 			p_error = parse_retrieve_error_action_error;
762 		} else {
763 		    warn_duplicate_val(attrib_num);
764 		}
765 		break;
766 		case key_yp_retrieve_error_attempts:
767 	    case key_retrieve_error_attempts:
768 		if (table_info->retrieveErrorRetry.attempts == NO_VALUE_SET) {
769 		    if (get_int_val(buf, &i, DEFAULT_RETRIEVE_ERROR_ATTEMPTS))
770 			table_info->retrieveErrorRetry.attempts = i;
771 		} else {
772 		    warn_duplicate_val(attrib_num);
773 		}
774 		break;
775 		case key_yp_retreive_error_timeout:
776 	    case key_retreive_error_timeout:
777 		if (table_info->retrieveErrorRetry.timeout ==
778 			(time_t)NO_VALUE_SET) {
779 		    if (get_time_t(buf, &timeout,
780 				DEFAULT_RETRIEVE_ERROR_TIME_OUT))
781 			table_info->retrieveErrorRetry.timeout = timeout;
782 		} else {
783 		    warn_duplicate_val(attrib_num);
784 		}
785 		break;
786 		case key_yp_store_error_action:
787 		if (table_info->storeError ==
788 			(__nis_store_error_t)NO_VALUE_SET) {
789 			if (strcasecmp("retry", buf) == 0)
790 				table_info->storeError = sto_retry;
791 			else if (strcasecmp("fail", buf) == 0)
792 				table_info->storeError = sto_fail;
793 			else
794 			p_error = parse_yp_store_error_action_error;
795 		} else {
796 			warn_duplicate_val(attrib_num);
797 		}
798 		break;
799 	    case key_store_error_action:
800 		if (table_info->storeError ==
801 			(__nis_store_error_t)NO_VALUE_SET) {
802 		    if (strcasecmp("system_error", buf) == 0)
803 			    table_info->storeError = system_error;
804 		    else if (strcasecmp("unavail", buf) == 0)
805 			    table_info->storeError = sto_unavail;
806 		    else if (strcasecmp("retry", buf) == 0)
807 			    table_info->storeError = sto_retry;
808 		    else
809 			p_error = parse_store_error_action_error;
810 		} else {
811 		    warn_duplicate_val(attrib_num);
812 		}
813 		break;
814 		case key_yp_store_error_attempts:
815 	    case key_store_error_attempts:
816 		if (table_info->storeErrorRetry.attempts == NO_VALUE_SET) {
817 		    if (get_int_val(buf, &i,
818 				DEFAULT_STORE_ERROR_ATTEMPTS))
819 			table_info->storeErrorRetry.attempts = i;
820 		} else {
821 		    warn_duplicate_val(attrib_num);
822 		}
823 		break;
824 		case key_yp_store_error_timeout:
825 	    case key_store_error_timeout:
826 		if (table_info->storeErrorRetry.timeout ==
827 			(time_t)NO_VALUE_SET) {
828 		    if (get_time_t(buf, &timeout,
829 				DEFAULT_STORE_ERROR_TIME_OUT))
830 			table_info->storeErrorRetry.timeout = timeout;
831 		} else {
832 		    warn_duplicate_val(attrib_num);
833 		}
834 		break;
835 	    case key_refresh_error_action:
836 		if (table_info->refreshError ==
837 			(__nis_refresh_error_t)NO_VALUE_SET) {
838 		    if (strcasecmp("continue_using", buf) == 0)
839 			    table_info->refreshError = continue_using;
840 		    else if (strcasecmp("cache_expired", buf) == 0)
841 			    table_info->refreshError = cache_expired;
842 		    else if (strcasecmp("tryagain", buf) == 0)
843 			    table_info->refreshError = tryagain;
844 		    else if (strcasecmp("retry", buf) == 0)
845 			    table_info->refreshError = ref_retry;
846 		    else if (strcasecmp("continue_using,retry", buf) == 0 ||
847 			strcasecmp("retry,continue_using", buf) == 0)
848 			    table_info->refreshError = continue_using_retry;
849 		    else
850 			p_error = parse_refresh_error_action_error;
851 		} else {
852 		    warn_duplicate_val(attrib_num);
853 		}
854 		break;
855 	    case key_refresh_error_attempts:
856 		if (table_info->refreshErrorRetry.attempts == NO_VALUE_SET) {
857 		    if (get_int_val(buf, &i, DEFAULT_REFRESH_ERROR_ATTEMPTS))
858 			table_info->refreshErrorRetry.attempts = i;
859 		} else {
860 		    warn_duplicate_val(attrib_num);
861 		}
862 		break;
863 	    case key_refresh_error_timeout:
864 		if (table_info->refreshErrorRetry.timeout ==
865 			(time_t)NO_VALUE_SET) {
866 		    if (get_time_t(buf, &timeout,
867 				DEFAULT_REFRESH_ERROR_TIME_OUT))
868 			table_info->refreshErrorRetry.timeout = timeout;
869 		} else {
870 		    warn_duplicate_val(attrib_num);
871 		}
872 		break;
873 		case key_yp_match_fetch:
874 	    case key_match_fetch:
875 		if (table_info->matchFetch ==
876 			(__nis_match_fetch_t)NO_VALUE_SET) {
877 		    if (strcasecmp("no_match_only", buf) == 0)
878 			    table_info->matchFetch = no_match_only;
879 		    else if (strcasecmp("always", buf) == 0)
880 			    table_info->matchFetch = mat_always;
881 		    else if (strcasecmp("never", buf) == 0)
882 			    table_info->matchFetch = mat_never;
883 		    else
884 			p_error = parse_match_fetch_error;
885 		} else {
886 		    warn_duplicate_val(attrib_num);
887 		}
888 		break;
889 	    case key_max_rpc_recsize:
890 		if (config_info->maxRPCRecordSize ==
891 			(int)NO_VALUE_SET) {
892 		    if (get_uint_val(buf, &i, RPC_MAXDATASIZE))
893 			    config_info->maxRPCRecordSize = i;
894 		} else {
895 		    warn_duplicate_val(attrib_num);
896 		}
897 		break;
898 	    default:
899 		p_error = parse_internal_error;
900 		break;
901 	}
902 
903 	return (p_error == no_parse_error ? 0 : -1);
904 }
905 
906 /*
907  * FUNCTION:	get_attrib_num
908  *
909  *	Get the attribute number for the corresponding keyword.
910  *
911  * RETURN VALUE:	attribute number on success,
912  *			key_bad on failure
913  *
914  * INPUT:		the attribute name string (assumed to be non-NULL)
915  */
916 
917 config_key
get_attrib_num(const char * s,int n)918 get_attrib_num(const char *s, int n)
919 {
920 	int		k;
921 	int		i;
922 	config_key	attrib_num = key_bad;
923 
924 	k = n < sizeof (_key_val) ? n : sizeof (_key_val) - 1;
925 	(void) memcpy(_key_val, s, k);
926 	_key_val[k] = '\0';
927 
928 	for (i = 0; i < sizeof (keyword_lookup) /
929 			sizeof (keyword_lookup[0]); i++) {
930 		if (strncasecmp(s, keyword_lookup[i].key_name, n) == 0 &&
931 				strlen(keyword_lookup[i].key_name) == n) {
932 			attrib_num = keyword_lookup[i].key_id;
933 			break;
934 		}
935 	}
936 
937 	if (attrib_num == key_bad) {
938 		p_error = parse_bad_key;
939 	}
940 
941 	return (attrib_num);
942 }
943 
944 /*
945  * FUNCTION:	get_timeval_t
946  *
947  *	Extract time from string
948  *
949  * RETURN VALUE:	TRUE if parsed
950  *			FALSE otherwise
951  *
952  * INPUT:		the attribute value string (assumed to be non-NULL)
953  */
954 
955 static bool_t
get_timeval_t(const char * s,int len,struct timeval * t,time_t default_val)956 get_timeval_t(
957 	const char	*s,
958 	int		len,
959 	struct timeval	*t,
960 	time_t		default_val)
961 {
962 	time_t		tv_sec		= 0;
963 	time_t		tv_usec		= 0;
964 	time_t		digit;
965 	time_t		mult		= 100000;
966 	bool_t		got_digit	= FALSE;
967 	bool_t		got_period	= FALSE;
968 	const char	*s_end		= s + len;
969 
970 	while (s < s_end && is_whitespace(*s))
971 		s++;
972 
973 	while (s < s_end && isdigit(*s)) {
974 		digit = (*s++) - '0';
975 		got_digit = TRUE;
976 		if (WILL_OVERFLOW_TIME(tv_sec, digit))
977 			tv_sec = TIME_MAX;
978 		else
979 			tv_sec = tv_sec * 10 + digit;
980 	}
981 	while (s < s_end && is_whitespace(*s))
982 		s++;
983 
984 	if (s < s_end && *s == PERIOD_CHAR) {
985 		s++;
986 		got_period = TRUE;
987 		while (s < s_end && isdigit(*s)) {
988 			got_digit = TRUE;
989 			digit = (*s++) - '0';
990 			tv_usec += digit * mult;
991 			mult /= 10;
992 		}
993 		while (s < s_end && is_whitespace(*s))
994 			s++;
995 	}
996 	if (s == s_end) {
997 		if (!got_digit) {
998 			if (got_period) {
999 				p_error = parse_bad_time_error;
1000 				return (FALSE);
1001 			}
1002 			tv_sec = default_val;
1003 		}
1004 		t->tv_sec = tv_sec;
1005 		t->tv_usec = tv_usec;
1006 	} else
1007 		p_error = parse_bad_time_error;
1008 
1009 	return (s == s_end);
1010 }
1011 
1012 /*
1013  * FUNCTION:	get_limit
1014  *
1015  *	Extract limit from string
1016  *
1017  * RETURN VALUE:	TRUE if parsed
1018  *			FALSE otherwise
1019  *
1020  * INPUT:		the attribute value string (assumed to be non-NULL)
1021  */
1022 
1023 
1024 static bool_t
get_limit(const char * s,int len,int * limit,int default_val)1025 get_limit(
1026 	const char	*s,
1027 	int		len,
1028 	int		*limit,
1029 	int		default_val)
1030 {
1031 	bool_t		got_digit	= FALSE;
1032 	int		l		= 0;
1033 	time_t		digit;
1034 	const char	*s_end		= s + len;
1035 
1036 	while (s < s_end && is_whitespace(*s))
1037 		s++;
1038 
1039 	while (s < s_end && isdigit(*s)) {
1040 		got_digit = TRUE;
1041 		digit = (*s++) - '0';
1042 		if (WILL_OVERFLOW_LIMIT(l, digit))
1043 			l = LIMIT_MAX;
1044 		else
1045 			l = l * 10 + digit;
1046 	}
1047 	while (s < s_end && is_whitespace(*s))
1048 		s++;
1049 	if (s == s_end) {
1050 		if (!got_digit)
1051 			l = default_val;
1052 		*limit = l;
1053 	} else
1054 		p_error = parse_bad_uint_error;
1055 
1056 	return (s == s_end);
1057 }
1058 
1059 /*
1060  * FUNCTION:	get_time_t
1061  *
1062  *	Parse a buffer containing a time_t string
1063  *
1064  * RETURN VALUE:	TRUE on success, FALSE on failure
1065  *
1066  * INPUT:		the attribute value string (assumed to be non-NULL)
1067  */
1068 
1069 static bool_t
get_time_t(const char * s,time_t * t,time_t default_val)1070 get_time_t(const char *s, time_t *t, time_t default_val)
1071 {
1072 	bool_t	got_digit	= FALSE;
1073 	time_t	timeout		= 0;
1074 
1075 	for (; is_whitespace(*s); s++)
1076 		;
1077 	while (isdigit(*s)) {
1078 		got_digit = TRUE;
1079 		if (WILL_OVERFLOW_TIME(timeout, *s))
1080 			timeout = TIME_MAX;
1081 		else
1082 			timeout = timeout * 10 + *s - '0';
1083 		s++;
1084 	}
1085 	for (; is_whitespace(*s); s++)
1086 		;
1087 	if (*s != '\0') {
1088 		p_error = parse_bad_int_error;
1089 		return (FALSE);
1090 	}
1091 	if (!got_digit)
1092 		timeout = default_val;
1093 
1094 	*t = timeout;
1095 	return (TRUE);
1096 }
1097 
1098 /*
1099  * FUNCTION:	get_uint_val
1100  *
1101  *	Parse a buffer containing a non-negative integer
1102  *
1103  * RETURN VALUE:	TRUE on success, FALSE on failure
1104  *
1105  * INPUT:		the attribute value string (assumed to be non-NULL)
1106  */
1107 
1108 static bool_t
get_uint_val(const char * s,int * val,int default_val)1109 get_uint_val(const char *s, int *val, int default_val)
1110 {
1111 	bool_t	got_digit	= FALSE;
1112 	int	v		= 0;
1113 
1114 	for (; is_whitespace(*s); s++)
1115 		;
1116 	while (isdigit(*s)) {
1117 		got_digit = TRUE;
1118 		if (WILL_OVERFLOW_INT(v, *s))
1119 			v = INT_MAX;
1120 		else
1121 			v = v * 10 + *s - '0';
1122 		s++;
1123 	}
1124 	for (; is_whitespace(*s); s++)
1125 		;
1126 	if (*s != '\0') {
1127 		p_error = parse_bad_int_error;
1128 		return (FALSE);
1129 	}
1130 
1131 	if (!got_digit)
1132 		v = default_val;
1133 
1134 	*val = v;
1135 	return (TRUE);
1136 }
1137 
1138 /*
1139  * FUNCTION:	get_int_val
1140  *
1141  *	Parse a buffer containing a non-negative integer
1142  *
1143  * RETURN VALUE:	TRUE on success, FALSE on failure
1144  *
1145  * INPUT:		the attribute value string (assumed to be non-NULL)
1146  */
1147 
1148 static bool_t
get_int_val(const char * s,int * val,int default_val)1149 get_int_val(const char *s, int *val, int default_val)
1150 {
1151 	bool_t	got_digit	= FALSE;
1152 	int	v		= 0;
1153 	bool_t	is_neg		= FALSE;
1154 
1155 	for (; is_whitespace(*s); s++)
1156 		;
1157 	if (*s == '-') {
1158 		is_neg = TRUE;
1159 		s++;
1160 	}
1161 	while (isdigit(*s)) {
1162 		got_digit = TRUE;
1163 		if (WILL_OVERFLOW_INT(v, *s))
1164 			v = INT_MAX;
1165 		else
1166 			v = v * 10 + *s - '0';
1167 		s++;
1168 	}
1169 	for (; is_whitespace(*s); s++)
1170 		;
1171 	if (*s != '\0') {
1172 		p_error = parse_bad_int_error;
1173 		return (FALSE);
1174 	}
1175 
1176 	if (!got_digit) {
1177 		if (is_neg) {
1178 			p_error = parse_bad_int_error;
1179 			return (FALSE);
1180 		}
1181 		v = default_val;
1182 	}
1183 	if (is_neg)
1184 		v = -v;
1185 	*val = v;
1186 	return (TRUE);
1187 }
1188 
1189 static void
warn_duplicate_val(config_key attrib_num)1190 warn_duplicate_val(
1191 	config_key attrib_num)
1192 {
1193 	const char	*key_name = "Unknown";
1194 	int		i;
1195 
1196 	if (warn_file == NULL || is_cmd_line_option(attrib_num))
1197 		return;
1198 
1199 	for (i = 0; i < sizeof (keyword_lookup) /
1200 			sizeof (keyword_lookup[0]); i++) {
1201 		if (attrib_num == keyword_lookup[i].key_id) {
1202 			key_name = keyword_lookup[i].key_name;
1203 			break;
1204 		}
1205 	}
1206 	if (cons != NULL) {
1207 		fprintf(cons,
1208 		"Warning: Duplicate value for %s in %s at line:%d\n",
1209 			key_name, warn_file, start_line_num);
1210 	} else {
1211 		syslog(LOG_INFO,
1212 			"Duplicate value for %s in %s at line:%d",
1213 			key_name, warn_file, start_line_num);
1214 	}
1215 }
1216 
1217 void
warn_duplicate_map(const char * db_id,config_key attrib_num)1218 warn_duplicate_map(
1219 	const char *db_id,
1220 	config_key attrib_num)
1221 {
1222 	const char	*key_name = "Unknown";
1223 	int		i;
1224 
1225 	if (warn_file == NULL)
1226 		return;
1227 
1228 	for (i = 0; i < sizeof (keyword_lookup) /
1229 			sizeof (keyword_lookup[0]); i++) {
1230 		if (attrib_num == keyword_lookup[i].key_id) {
1231 			key_name = keyword_lookup[i].key_name;
1232 			break;
1233 		}
1234 	}
1235 	if (cons != NULL) {
1236 		fprintf(cons,
1237 		"Warning: Duplicate value for %s:%s in %s at line:%d\n",
1238 			key_name, db_id, warn_file, start_line_num);
1239 	} else {
1240 		syslog(LOG_INFO,
1241 			"Duplicate value for %s:%s in %s at line:%d",
1242 			key_name, db_id, warn_file, start_line_num);
1243 	}
1244 }
1245