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