1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * ldapaddent.c
30  *
31  * Utility to add /etc files into LDAP.
32  * Can also be used to dump entries from a ldap container in /etc format.
33  */
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <libintl.h>
38 #include <strings.h>
39 #include <sys/param.h>
40 #include <ctype.h>
41 #include <sys/types.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45 #include <locale.h>
46 #include <syslog.h>
47 
48 #undef opaque
49 
50 #include <nss_dbdefs.h>
51 #include <netdb.h>
52 #include <rpc/rpcent.h>
53 #include <grp.h>
54 #include <pwd.h>
55 #include <shadow.h>
56 #include <sys/systeminfo.h>
57 #include "ns_internal.h"
58 #include "ldapaddent.h"
59 
60 #define	OP_ADD	0
61 #define	OP_DUMP	3
62 
63 static struct ttypelist_t {
64 	char *ttype;		/* type tag */
65 	int (*genent)(char *, int(*)());
66 				/* routine to turn line into ldap entries */
67 	void (*dump)(ns_ldap_result_t *);
68 				/* routine to print ldap containers */
69 	int (*filedbmline)();	/* routine to turn file line into dbm line */
70 	char *objclass;		/* Objectclass for the servicetype */
71 } *tt;
72 
73 char	parse_err_msg [PARSE_ERR_MSG_LEN];
74 int	continue_onerror = 0;  /* do not exit on error */
75 
76 static int get_basedn(char *service, char **basedn);
77 static int check_ipaddr(char *addr, char **newaddr);
78 
79 extern	int	optind;
80 extern	char	*optarg;
81 
82 extern	char	*__nis_quote_key(const char *, char *, int);
83 /* from ns_internal.h */
84 extern	int __s_api_prepend_automountmapname_to_dn(
85 	const char *, char **, ns_ldap_error_t **);
86 
87 static char	*inputbasedn = NULL;
88 static char	*databasetype = NULL;
89 static int	exit_val = 0;
90 static unsigned	nent_add = 0;
91 static FILE	*etcf = 0;
92 static ns_cred_t	authority;
93 unsigned	flags = 0;
94 
95 static void
96 perr(ns_ldap_error_t *e)
97 {
98 	if (e)
99 		(void) fprintf(stderr, gettext("%d: %s\n"),
100 				e->status, e->message);
101 }
102 
103 
104 static int
105 ascii_to_int(char *str)
106 {
107 	int i;
108 	char *c = str;
109 
110 	if (c == NULL || *c == '\0')
111 		return (-1);
112 
113 	while (c != '\0' && *c == ' ')
114 		c++;
115 	if (*c == '\0')
116 		return (-1);
117 
118 	for (i = 0; i < strlen(c); i++)
119 		if (!isdigit(c[i]))
120 			return (-1);
121 
122 	return (atoi(c));
123 }
124 
125 /*
126  * Internet network address interpretation routine.
127  * The library routines call this routine to interpret
128  * network numbers.
129  */
130 static in_addr_t
131 encode_network(const char *cp)
132 {
133 	in_addr_t val;
134 	int base;
135 	ptrdiff_t n;
136 	char c;
137 	in_addr_t parts[4], *pp = parts;
138 	int i;
139 
140 again:
141 	val = 0; base = 10;
142 	if (*cp == '0') {
143 		if (*++cp == 'x' || *cp == 'X')
144 			base = 16, cp++;
145 		else
146 			base = 8;
147 	}
148 	while ((c = *cp) != NULL) {
149 		if (isdigit(c)) {
150 			if ((c - '0') >= base)
151 			    break;
152 			val = (val * base) + (c - '0');
153 			cp++;
154 			continue;
155 		}
156 		if (base == 16 && isxdigit(c)) {
157 			val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
158 			cp++;
159 			continue;
160 		}
161 		break;
162 	}
163 	if (*cp == '.') {
164 		if (pp >= parts + 4)
165 			return ((in_addr_t)-1);
166 		*pp++ = val, cp++;
167 		goto again;
168 	}
169 	if (*cp && !isspace(*cp))
170 		return ((in_addr_t)-1);
171 	*pp++ = val;
172 	n = pp - parts;
173 	if (n > 4)
174 		return ((in_addr_t)-1);
175 	for (val = 0, i = 0; i < n; i++) {
176 		val <<= 8;
177 		val |= parts[i] & 0xff;
178 	}
179 	for (/* no init */; i < 4; i++)
180 		val <<= 8;
181 	return (val);
182 }
183 
184 static void
185 replace_tab2space(char *str)
186 {
187 	int i = 0;
188 
189 	while ((str) && (str[i])) {
190 		if (str[i] == '\t')
191 			str[i] = ' ';
192 		i++;
193 	}
194 }
195 
196 static int
197 blankline(char *line)
198 {
199 	char *p;
200 
201 	for (p = line; *p; p++)
202 		if (*p != ' ' && *p != '\t')
203 			return (0);
204 	return (1);
205 }
206 
207 /*
208  * check whether the token <tok> is a triplet,
209  * i. e. <tok> := (<hostname>,<username>,<domainname>)
210  * where <hostname>, <username>, <domainname> are IA5String
211  * <tok> supposes to contain NO spaces and start with '('
212  */
213 static int
214 is_triplet(char *tok)
215 {
216 	char *s;
217 	return (strchr(++tok, '(') == NULL &&		/* no more '(' */
218 		(s = strchr(tok, ')')) != NULL &&	/* find ')' */
219 		!*++s &&				/* ')' ends token */
220 		(tok = strchr(tok, ',')) != NULL &&	/* host up to ',' */
221 		(tok = strchr(++tok, ',')) != NULL &&	/* user up to ',' */
222 		strchr(++tok, ',') == NULL);		/* no more ',' */
223 }
224 
225 static void
226 line_buf_expand(struct line_buf *line)
227 {
228 	line->alloc += BUFSIZ;
229 	line->str = (char *)realloc(line->str, line->alloc);
230 
231 	if (line->str == NULL) {
232 		(void) fprintf(stderr,
233 		    gettext("line_buf_expand: out of memory\n"));
234 		exit(1);
235 	}
236 }
237 
238 static void
239 line_buf_init(struct line_buf *line)
240 {
241 	(void) memset((char *)line, 0, sizeof (*line));
242 	line_buf_expand(line);
243 }
244 
245 static int
246 __s_add_attr(ns_ldap_entry_t *e, char *attrname, char *value)
247 {
248 	ns_ldap_attr_t	*a;
249 	char		*v;
250 
251 	a = (ns_ldap_attr_t *)calloc(1, sizeof (ns_ldap_attr_t));
252 	if (a == NULL)
253 		return (NS_LDAP_MEMORY);
254 	a->attrname = strdup(attrname);
255 	if (a->attrname == NULL) {
256 		free(a);
257 		return (NS_LDAP_MEMORY);
258 	}
259 	a->attrvalue = (char **)calloc(1, sizeof (char **));
260 	if (a->attrvalue == NULL) {
261 		free(a->attrname);
262 		free(a);
263 		return (NS_LDAP_MEMORY);
264 	}
265 	a->value_count = 1;
266 	a->attrvalue[0] = NULL;
267 	v = strdup(value);
268 	if (v == NULL) {
269 		free(a->attrname);
270 		free(a->attrvalue);
271 		free(a);
272 		return (NS_LDAP_MEMORY);
273 	}
274 	a->attrvalue[0] = v;
275 	e->attr_pair[e->attr_count] = a;
276 	e->attr_count++;
277 	return (NS_LDAP_SUCCESS);
278 }
279 
280 static int
281 __s_add_attrlist(ns_ldap_entry_t *e, char *attrname, char **argv)
282 {
283 	ns_ldap_attr_t	*a;
284 	char		*v;
285 	char		**av;
286 	int		i, j;
287 
288 	a = (ns_ldap_attr_t *)calloc(1, sizeof (ns_ldap_attr_t));
289 	if (a == NULL)
290 		return (NS_LDAP_MEMORY);
291 	a->attrname = strdup(attrname);
292 	if (a->attrname == NULL) {
293 		free(a);
294 		return (NS_LDAP_MEMORY);
295 	}
296 
297 	for (i = 0, av = argv; *av != NULL; av++, i++)
298 		;
299 
300 	a->attrvalue = (char **)calloc(i, sizeof (char **));
301 
302 	if (a->attrvalue == NULL) {
303 		free(a->attrname);
304 		free(a);
305 		return (NS_LDAP_MEMORY);
306 	}
307 	a->value_count = i;
308 	for (j = 0; j < i; j++) {
309 		v = strdup(argv[j]);
310 		if (v == NULL) {
311 			free(a->attrname);
312 			free(a->attrvalue);
313 			free(a);
314 			return (NS_LDAP_MEMORY);
315 		}
316 		a->attrvalue[j] = v;
317 	}
318 	e->attr_pair[e->attr_count] = a;
319 	e->attr_count++;
320 	return (NS_LDAP_SUCCESS);
321 }
322 
323 static ns_ldap_entry_t *
324 __s_mk_entry(char **objclass, int max_attr)
325 {
326 	ns_ldap_entry_t *e;
327 	e = (ns_ldap_entry_t *)calloc(1, sizeof (ns_ldap_entry_t));
328 	if (e == NULL)
329 		return (NULL);
330 	e->attr_pair = (ns_ldap_attr_t **)calloc(max_attr+1,
331 						sizeof (ns_ldap_attr_t *));
332 	if (e->attr_pair == NULL) {
333 		free(e);
334 		return (NULL);
335 	}
336 	e->attr_count = 0;
337 	if (__s_add_attrlist(e, "objectClass", objclass) != NS_LDAP_SUCCESS) {
338 		free(e->attr_pair);
339 		free(e);
340 		return (NULL);
341 	}
342 	return (e);
343 }
344 
345 static void
346 ldap_freeEntry(ns_ldap_entry_t *ep)
347 {
348 	int		j, k = 0;
349 
350 	if (ep == NULL)
351 		return;
352 
353 	if (ep->attr_pair == NULL) {
354 		free(ep);
355 		return;
356 	}
357 	for (j = 0; j < ep->attr_count; j++) {
358 		if (ep->attr_pair[j] == NULL)
359 			continue;
360 		if (ep->attr_pair[j]->attrname)
361 			free(ep->attr_pair[j]->attrname);
362 		if (ep->attr_pair[j]->attrvalue) {
363 			for (k = 0; (k < ep->attr_pair[j]->value_count) &&
364 				    (ep->attr_pair[j]->attrvalue[k]); k++) {
365 				free(ep->attr_pair[j]->attrvalue[k]);
366 			}
367 			free(ep->attr_pair[j]->attrvalue);
368 		}
369 		free(ep->attr_pair[j]);
370 	}
371 	free(ep->attr_pair);
372 	free(ep);
373 }
374 
375 static int
376 addentry(void *entry, int mod)
377 {
378 	int		 result = 0;
379 	ns_ldap_error_t	 *eres = NULL;
380 	int		rc = 1;
381 
382 
383 	/*  adds entry into the LDAP tree */
384 	if (mod)
385 		result = __ns_ldap_addTypedEntry(databasetype, inputbasedn,
386 		    entry, 0, &authority, NS_LDAP_FOLLOWREF, &eres);
387 	else
388 		result = __ns_ldap_addTypedEntry(databasetype, inputbasedn,
389 		    entry, 1, &authority, NS_LDAP_FOLLOWREF, &eres);
390 	/*
391 	 *  Return	0 on success
392 	 *		LDAP_ALREADY_EXISTS if entry exists already
393 	 *		1 for all other non-fatal errors.
394 	 *  Exit on fatal errors.
395 	 */
396 	switch (result) {
397 	case NS_LDAP_SUCCESS:
398 		nent_add++;
399 		rc = 0;
400 		break;
401 
402 	case NS_LDAP_OP_FAILED:
403 		(void) fprintf(stderr, gettext("operation failed.\n"));
404 		rc = 1;
405 		break;
406 
407 	case NS_LDAP_INVALID_PARAM:
408 		(void) fprintf(stderr,
409 		    gettext("invalid parameter(s) passed.\n"));
410 		rc = 1;
411 		break;
412 
413 	case NS_LDAP_NOTFOUND:
414 		(void) fprintf(stderr, gettext("entry not found.\n"));
415 		rc = 1;
416 		break;
417 
418 	case NS_LDAP_MEMORY:
419 		(void) fprintf(stderr,
420 		    gettext("internal memory allocation error.\n"));
421 		exit(1);
422 		break;
423 
424 	case NS_LDAP_CONFIG:
425 		(void) fprintf(stderr,
426 		    gettext("LDAP Configuration problem.\n"));
427 		perr(eres);
428 		exit(1);
429 		break;
430 
431 	case NS_LDAP_PARTIAL:
432 		(void) fprintf(stderr,
433 		    gettext("partial result returned\n"));
434 		perr(eres);
435 		rc = 1;
436 		break;
437 
438 	case NS_LDAP_INTERNAL:
439 		if (eres->status == LDAP_ALREADY_EXISTS)
440 			rc = eres->status;
441 		else {
442 			rc = 1;
443 			perr(eres);
444 		}
445 		break;
446 	}
447 
448 	if (eres)
449 		(void) __ns_ldap_freeError(&eres);
450 	return (rc);
451 }
452 
453 
454 /*
455  * usage(char *msg)
456  * Display usage message to STDERR.
457  */
458 static void
459 usage(char *msg) {
460 
461 	if (msg)
462 		(void) fprintf(stderr, gettext("%s\n"), msg);
463 
464 	(void) fprintf(stderr, gettext(
465 	    "usage: ldapaddent [ -cpv ] [ -a authenticationMethod ]\n"
466 	    "[ -b baseDN ] -D bindDN -w bind_password [ -f file ] database\n\n"
467 	    "usage: ldapaddent -d [ -cpv ] [ -a authenticationMethod ]\n"
468 	    "[ -b baseDN ] [ -D bindDN ] [ -w bind_password ] database\n"));
469 	exit(1);
470 }
471 
472 /*
473  * Determine if the given string is an IP address (IPv4 or IPv6).
474  * If so, it's converted to the preferred form (rfc2373) and
475  * *newaddr will point to the new address.
476  *
477  * Returns	-2		: inet_ntop error
478  *		-1		: not an IP address
479  *		0		: unsupported IP address (future use)
480  *		AF_INET		: IPv4
481  *		AF_INET6	: IPv6
482  */
483 static int
484 check_ipaddr(char *addr, char **newaddr) {
485 	ipaddr_t	addr_ipv4 = 0;
486 	in6_addr_t	addr_ipv6;
487 
488 	/* IPv6 */
489 	if (inet_pton(AF_INET6, addr, &addr_ipv6) == 1) {
490 		if (newaddr == NULL)
491 			return (AF_INET6);
492 
493 		/* Convert IPv4-mapped IPv6 address to IPv4 */
494 		if (IN6_IS_ADDR_V4MAPPED(&addr_ipv6) ||
495 					IN6_IS_ADDR_V4COMPAT(&addr_ipv6)) {
496 			IN6_V4MAPPED_TO_IPADDR(&addr_ipv6, addr_ipv4);
497 			if ((*newaddr = calloc(1, INET_ADDRSTRLEN)) == NULL) {
498 				(void) fprintf(stderr,
499 				    gettext("out of memory\n"));
500 				exit(1);
501 			}
502 			if (inet_ntop(AF_INET, &addr_ipv4, *newaddr,
503 			    INET_ADDRSTRLEN))
504 				return (AF_INET6);
505 			free(*newaddr);
506 			return (-2);
507 		}
508 
509 		/* Processing general IPv6 addresses */
510 		if ((*newaddr = calloc(1, INET6_ADDRSTRLEN)) == NULL) {
511 			(void) fprintf(stderr, gettext("out of memory\n"));
512 			exit(1);
513 		}
514 		if (inet_ntop(AF_INET6, &addr_ipv6, *newaddr, INET6_ADDRSTRLEN))
515 			return (AF_INET6);
516 		free(*newaddr);
517 		return (-2);
518 	}
519 
520 	/* Processing IPv4 addresses of the type d.d.d.d. */
521 	if (inet_pton(AF_INET, addr, &addr_ipv4) == 1) {
522 		if (newaddr == NULL)
523 			return (AF_INET);
524 		if ((*newaddr = calloc(1, INET_ADDRSTRLEN)) == NULL) {
525 			(void) fprintf(stderr, gettext("out of memory\n"));
526 			exit(1);
527 		}
528 		if (inet_ntop(AF_INET, &addr_ipv4, *newaddr, INET_ADDRSTRLEN))
529 			return (AF_INET);
530 		free(*newaddr);
531 		return (-2);
532 	}
533 
534 	/* Processing IPv4 addresses d.d.d , d.d and d */
535 	if (inet_addr(addr) != (in_addr_t)-1) {
536 		if (newaddr == NULL)
537 			return (AF_INET);
538 		if ((*newaddr = strdup(addr)) == NULL) {
539 			(void) fprintf(stderr, gettext("out of memory\n"));
540 			exit(1);
541 		}
542 		return (AF_INET);
543 	}
544 
545 	return (-1);
546 }
547 
548 static int
549 genent_hosts(char *line, int (*cback)())
550 {
551 	char buf[BUFSIZ+1];
552 	char *t;
553 	entry_col ecol[4];
554 	char *cname, *pref_addr;
555 	int ctr = 0, retval = 1;
556 	int rc = GENENT_OK, af;
557 
558 	struct hostent  data;
559 	char *alias;
560 
561 	/*
562 	 * don't clobber our argument
563 	 */
564 	if (strlen(line) >= sizeof (buf)) {
565 		(void) strcpy(parse_err_msg, "line too long");
566 		return (GENENT_PARSEERR);
567 	}
568 	(void) strcpy(buf, line);
569 
570 	/*
571 	 * clear column data
572 	 */
573 	(void) memset((char *)ecol, 0, sizeof (ecol));
574 
575 	/*
576 	 * comment (col 3)
577 	 */
578 	t = strchr(buf, '#');
579 	if (t) {
580 		*t++ = 0;
581 		ecol[3].ec_value.ec_value_val = t;
582 		ecol[3].ec_value.ec_value_len = strlen(t)+1;
583 	} else {
584 		ecol[3].ec_value.ec_value_val = "";
585 		ecol[3].ec_value.ec_value_len = 0;
586 	}
587 
588 
589 	/*
590 	 * addr(col 2)
591 	 */
592 	if ((t = strtok(buf, " \t")) == 0) {
593 		(void) strcpy(parse_err_msg, "no host");
594 		return (GENENT_PARSEERR);
595 	}
596 
597 	af = check_ipaddr(t, &pref_addr);
598 	if (af == -2) {
599 		(void) strcpy(parse_err_msg, "Internal error");
600 	} else if (af == -1) {
601 		(void) snprintf(parse_err_msg, sizeof (parse_err_msg),
602 		    "Invalid IP address: %s", t);
603 	} else if (flags & F_VERBOSE) {
604 		if ((strncasecmp(t, pref_addr, strlen(t))) != 0) {
605 			(void) fprintf(stdout,
606 			    gettext("IP address %s converted to %s\n"),
607 			    t, pref_addr);
608 		}
609 	}
610 
611 	if (af < 0) {
612 		(void) fprintf(stderr, gettext("%s\n"), parse_err_msg);
613 		if (continue_onerror == 0)
614 			return (GENENT_CBERR);
615 		else
616 			return (rc);
617 	}
618 
619 	ecol[2].ec_value.ec_value_val = pref_addr;
620 	ecol[2].ec_value.ec_value_len = strlen(pref_addr)+1;
621 
622 	/*
623 	 * cname (col 0)
624 	 */
625 	if ((t = strtok(NULL, " \t")) == 0) {
626 		(void) strcpy(parse_err_msg, "no cname");
627 		return (GENENT_PARSEERR);
628 	}
629 	ecol[0].ec_value.ec_value_val = t;
630 	ecol[0].ec_value.ec_value_len = strlen(t)+1;
631 	cname = t;
632 
633 
634 	/* build entry */
635 	if ((data.h_addr_list = (char **)calloc(2, sizeof (char **))) == NULL) {
636 		(void) fprintf(stderr, gettext("out of memory\n"));
637 		exit(1);
638 	}
639 	data.h_addr_list[0] = strdup(ecol[2].ec_value.ec_value_val);
640 	data.h_addr_list[1] = NULL;
641 
642 	free(pref_addr);
643 	data.h_name = strdup(ecol[0].ec_value.ec_value_val);
644 
645 	/*
646 	 * name (col 1)
647 	 */
648 
649 	data.h_aliases = NULL;
650 
651 	do {
652 		/*
653 		 * don't clobber comment in canonical entry
654 		 */
655 
656 		/* This call to AddEntry may move out of the loop */
657 		/* This is because we have to call the function just once */
658 		if (t != cname && strcasecmp(t, cname) == 0)
659 			continue;
660 		if (strcasecmp(t, ecol[0].ec_value.ec_value_val) == 0)
661 			continue;
662 
663 		ecol[1].ec_value.ec_value_val = t;
664 		ecol[1].ec_value.ec_value_len = strlen(t)+1;
665 
666 		ctr++;
667 		alias = strdup(ecol[1].ec_value.ec_value_val);
668 		if ((data.h_aliases = (char **)realloc(data.h_aliases,
669 			ctr * sizeof (char **))) == NULL) {
670 			(void) fprintf(stderr, gettext("out of memory\n"));
671 			exit(1);
672 		}
673 		data.h_aliases[ctr-1] = alias;
674 
675 		/*
676 		 * only put comment in canonical entry
677 		 */
678 		ecol[3].ec_value.ec_value_val = 0;
679 		ecol[3].ec_value.ec_value_len = 0;
680 
681 	} while (t = strtok(NULL, " \t"));
682 
683 	/* End the list of all the aliases by NULL */
684 	if ((data.h_aliases = (char **)realloc(data.h_aliases,
685 		(ctr + 1) * sizeof (char **))) == NULL) {
686 		(void) fprintf(stderr, gettext("out of memory\n"));
687 		exit(1);
688 	}
689 	data.h_aliases[ctr] = NULL;
690 
691 	if (flags & F_VERBOSE)
692 		(void) fprintf(stdout,
693 		    gettext("Adding entry : cn=%s+ipHostNumber=%s\n"),
694 		    data.h_name, data.h_addr_list[0]);
695 
696 	retval = (*cback)(&data, 0);
697 
698 	if (retval == LDAP_ALREADY_EXISTS) {
699 		if (continue_onerror)
700 			(void) fprintf(stderr,
701 				gettext("Entry: cn=%s+ipHostNumber=%s "
702 					"already Exists -skipping it\n"),
703 					data.h_name, data.h_addr_list[0]);
704 		else {
705 			rc = GENENT_CBERR;
706 			(void) fprintf(stderr,
707 				gettext("Entry: cn=%s+ipHostNumber=%s"
708 					" already Exists\n"),
709 					data.h_name, data.h_addr_list[0]);
710 		}
711 	} else if (retval)
712 		rc = GENENT_CBERR;
713 
714 	free(data.h_name);
715 	free(data.h_aliases);
716 	free(data.h_addr_list);
717 
718 	return (rc);
719 }
720 
721 
722 
723 static void
724 dump_hosts(ns_ldap_result_t *res)
725 {
726 	ns_ldap_attr_t	*attrptr = NULL, *cn = NULL, *iphostnumber = NULL;
727 	int		 i, j;
728 	char		*name; /* host name */
729 
730 	if (res == NULL || res->entry == NULL)
731 		return;
732 	for (i = 0; i < res->entry->attr_count; i++) {
733 		attrptr = res->entry->attr_pair[i];
734 		if (strcasecmp(attrptr->attrname, "cn") == 0)
735 			cn = attrptr;
736 		else if (strcasecmp(attrptr->attrname, "iphostnumber") == 0)
737 			iphostnumber = attrptr;
738 	}
739 	/* sanity check */
740 	if (cn == NULL || cn->attrvalue == NULL || cn->attrvalue[0] == NULL ||
741 	    iphostnumber == NULL || iphostnumber->attrvalue == NULL ||
742 	    iphostnumber->attrvalue[0] == NULL)
743 		return;
744 
745 	if ((name = __s_api_get_canonical_name(res->entry, cn, 1)) == NULL)
746 		return;
747 
748 	/* ip host/ipnode number */
749 	if (strlen(iphostnumber->attrvalue[0]) <= INET_ADDRSTRLEN)
750 		/* IPV4 or IPV6 but <= NET_ADDRSTRLEN */
751 		(void) fprintf(stdout, "%-18s", iphostnumber->attrvalue[0]);
752 	else
753 		/* IPV6 */
754 		(void) fprintf(stdout, "%-48s", iphostnumber->attrvalue[0]);
755 
756 	/* host/ipnode name */
757 	(void) fprintf(stdout, "%s ", name);
758 
759 	/* aliases */
760 	for (j = 0; j < cn->value_count; j++) {
761 		if (cn->attrvalue[j]) {
762 			if (strcasecmp(name, cn->attrvalue[j]) == 0)
763 				/* skip host name */
764 				continue;
765 			(void) fprintf(stdout, "%s ", cn->attrvalue[j]);
766 		}
767 	}
768 
769 	/* end of line */
770 	(void) fprintf(stdout, "\n");
771 }
772 
773 /*
774  * /etc/rpc
775  */
776 
777 static int
778 genent_rpc(char *line, int (*cback)())
779 {
780 	char buf[BUFSIZ+1];
781 	char *t;
782 	entry_col ecol[4];
783 	char *cname;
784 
785 	struct rpcent	data;
786 	char *alias;
787 	int ctr = 0;
788 	int retval = 1;
789 	int rc = GENENT_OK;
790 
791 	/*
792 	 * don't clobber our argument
793 	 */
794 	if (strlen(line) >= sizeof (buf)) {
795 		(void) strcpy(parse_err_msg, "line too long");
796 		return (GENENT_PARSEERR);
797 	}
798 	(void) strcpy(buf, line);
799 
800 	/*
801 	 * clear column data
802 	 */
803 	(void) memset((char *)ecol, 0, sizeof (ecol));
804 
805 	/*
806 	 * comment (col 3)
807 	 */
808 	t = strchr(buf, '#');
809 	if (t) {
810 		*t++ = 0;
811 		ecol[3].ec_value.ec_value_val = t;
812 		ecol[3].ec_value.ec_value_len = strlen(t)+1;
813 	} else {
814 		ecol[3].ec_value.ec_value_val = 0;
815 		ecol[3].ec_value.ec_value_len = 0;
816 	}
817 
818 	/*
819 	 * cname(col 0)
820 	 */
821 	if ((t = strtok(buf, " \t")) == 0) {
822 		(void) strcpy(parse_err_msg, "no number");
823 		return (GENENT_PARSEERR);
824 	}
825 	ecol[0].ec_value.ec_value_val = t;
826 	ecol[0].ec_value.ec_value_len = strlen(t)+1;
827 	cname = t;
828 
829 	/*
830 	 * number (col 2)
831 	 */
832 	if ((t = strtok(NULL, " \t")) == 0) {
833 		(void) strcpy(parse_err_msg, "no number");
834 		return (GENENT_PARSEERR);
835 	}
836 	ecol[2].ec_value.ec_value_val = t;
837 	ecol[2].ec_value.ec_value_len = strlen(t)+1;
838 
839 
840 	/*
841 	 * build entry
842 	 */
843 
844 	data.r_name = strdup(ecol[0].ec_value.ec_value_val);
845 	if (ecol[2].ec_value.ec_value_val != NULL &&
846 		ecol[2].ec_value.ec_value_val[0] != '\0') {
847 
848 		data.r_number = ascii_to_int(ecol[2].ec_value.ec_value_val);
849 		if (data.r_number == -1) {
850 			(void) snprintf(parse_err_msg, sizeof (parse_err_msg),
851 			    "invalid program number: %s",
852 			    ecol[2].ec_value.ec_value_val);
853 		return (GENENT_PARSEERR);
854 		}
855 	} else
856 		data.r_number = -1;
857 
858 	/*
859 	 * name (col 1)
860 	 */
861 	t = cname;
862 	data.r_aliases = NULL;
863 	do {
864 
865 		/*
866 		 * don't clobber comment in canonical entry
867 		 */
868 		if (t != cname && strcasecmp(t, cname) == 0)
869 			continue;
870 		if (strcasecmp(t, ecol[0].ec_value.ec_value_val) == 0)
871 			continue;
872 
873 		ecol[1].ec_value.ec_value_val = t;
874 		ecol[1].ec_value.ec_value_len = strlen(t)+1;
875 
876 		ctr++;
877 		alias = strdup(ecol[1].ec_value.ec_value_val);
878 		if ((data.r_aliases = (char **)realloc(data.r_aliases,
879 			ctr * sizeof (char **))) == NULL) {
880 			(void) fprintf(stderr, gettext("out of memory\n"));
881 			exit(1);
882 		}
883 		data.r_aliases[ctr-1] = alias;
884 
885 
886 		/*
887 		 * only put comment in canonical entry
888 		 */
889 		ecol[3].ec_value.ec_value_val = 0;
890 		ecol[3].ec_value.ec_value_len = 0;
891 
892 	} while (t = strtok(NULL, " \t"));
893 
894 	/* End the list of all the aliases by NULL */
895 	if ((data.r_aliases = (char **)realloc(data.r_aliases,
896 		(ctr + 1) * sizeof (char **))) == NULL) {
897 		(void) fprintf(stderr, gettext("out of memory\n"));
898 		exit(1);
899 	}
900 	data.r_aliases[ctr] = NULL;
901 
902 	if (flags & F_VERBOSE)
903 		(void) fprintf(stdout,
904 		    gettext("Adding entry : %s\n"), data.r_name);
905 
906 	retval = (*cback)(&data, 0);
907 
908 	if (retval == LDAP_ALREADY_EXISTS) {
909 		if (continue_onerror)
910 			(void) fprintf(stderr,
911 			gettext("Entry: %s - already Exists, skipping it.\n"),
912 			data.r_name);
913 		else {
914 			rc = GENENT_CBERR;
915 			(void) fprintf(stderr,
916 				gettext("Entry: %s - already Exists\n"),
917 				data.r_name);
918 		}
919 	} else if (retval)
920 		rc = GENENT_CBERR;
921 
922 	free(data.r_name);
923 	free(data.r_aliases);
924 
925 	return (rc);
926 }
927 
928 
929 
930 static void
931 dump_rpc(ns_ldap_result_t *res)
932 {
933 	ns_ldap_attr_t	*attrptr = NULL, *cn = NULL, *rpcnumber = NULL;
934 	int		 i, j;
935 	char		*name; /* rpc name */
936 
937 	if (res == NULL || res->entry == NULL)
938 		return;
939 	for (i = 0; i < res->entry->attr_count; i++) {
940 		attrptr = res->entry->attr_pair[i];
941 		if (strcasecmp(attrptr->attrname, "cn") == 0)
942 			cn = attrptr;
943 		else if (strcasecmp(attrptr->attrname, "oncRpcNumber") == 0)
944 			rpcnumber = attrptr;
945 	}
946 	/* sanity check */
947 	if (cn == NULL || cn->attrvalue == NULL || cn->attrvalue[0] == NULL ||
948 	    rpcnumber == NULL || rpcnumber->attrvalue == NULL ||
949 	    rpcnumber->attrvalue[0] == NULL)
950 		return;
951 
952 	if ((name = __s_api_get_canonical_name(res->entry, cn, 1)) == NULL)
953 		return;
954 
955 	/* rpc name */
956 	if (strlen(name) < 8)
957 		(void) fprintf(stdout, "%s\t\t", name);
958 	else
959 		(void) fprintf(stdout, "%s\t", name);
960 
961 	/* rpc number */
962 	(void) fprintf(stdout, "%-8s", rpcnumber->attrvalue[0]);
963 
964 
965 	/* aliases */
966 	for (j = 0; j < cn->value_count; j++) {
967 		if (cn->attrvalue[j]) {
968 			if (strcasecmp(name, cn->attrvalue[j]) == 0)
969 				/* skip rpc name */
970 				continue;
971 			(void) fprintf(stdout, "%s ", cn->attrvalue[j]);
972 		}
973 	}
974 
975 	/* end of line */
976 	(void) fprintf(stdout, "\n");
977 
978 }
979 
980 /*
981  * /etc/protocols
982  *
983  */
984 
985 static int
986 genent_protocols(char *line, int (*cback)())
987 {
988 	char buf[BUFSIZ+1];
989 	char *t;
990 	entry_col ecol[4];
991 	char *cname;
992 
993 	struct protoent	data;
994 	char *alias;
995 	int ctr = 0;
996 	int retval = 1;
997 	int rc = GENENT_OK;
998 
999 	/*
1000 	 * don't clobber our argument
1001 	 */
1002 	if (strlen(line) >= sizeof (buf)) {
1003 		(void) strcpy(parse_err_msg, "line too long");
1004 		return (GENENT_PARSEERR);
1005 	}
1006 	(void) strcpy(buf, line);
1007 
1008 	/*
1009 	 * clear column data
1010 	 */
1011 	(void) memset((char *)ecol, 0, sizeof (ecol));
1012 
1013 	/*
1014 	 * comment (col 3)
1015 	 */
1016 	t = strchr(buf, '#');
1017 	if (t) {
1018 		*t++ = 0;
1019 		ecol[3].ec_value.ec_value_val = t;
1020 		ecol[3].ec_value.ec_value_len = strlen(t)+1;
1021 	} else {
1022 		ecol[3].ec_value.ec_value_val = 0;
1023 		ecol[3].ec_value.ec_value_len = 0;
1024 	}
1025 
1026 	/*
1027 	 * cname(col 0)
1028 	 */
1029 	if ((t = strtok(buf, " \t")) == 0) {
1030 		(void) strcpy(parse_err_msg, "no number");
1031 		return (GENENT_PARSEERR);
1032 	}
1033 	ecol[0].ec_value.ec_value_val = t;
1034 	ecol[0].ec_value.ec_value_len = strlen(t)+1;
1035 	cname = t;
1036 
1037 	/*
1038 	 * number (col 2)
1039 	 */
1040 	if ((t = strtok(NULL, " \t")) == 0) {
1041 		(void) strcpy(parse_err_msg, "no number");
1042 		return (GENENT_PARSEERR);
1043 	}
1044 	ecol[2].ec_value.ec_value_val = t;
1045 	ecol[2].ec_value.ec_value_len = strlen(t)+1;
1046 
1047 
1048 	/*
1049 	 * build entry
1050 	 */
1051 	data.p_name = strdup(ecol[0].ec_value.ec_value_val);
1052 
1053 	if (ecol[2].ec_value.ec_value_val != NULL &&
1054 		ecol[2].ec_value.ec_value_val[0] != '\0') {
1055 
1056 		data.p_proto = ascii_to_int(ecol[2].ec_value.ec_value_val);
1057 		if (data.p_proto == -1) {
1058 			(void) snprintf(parse_err_msg, sizeof (parse_err_msg),
1059 			    "invalid protocol number: %s",
1060 			    ecol[2].ec_value.ec_value_val);
1061 		return (GENENT_PARSEERR);
1062 		}
1063 	} else
1064 		data.p_proto = -1;
1065 
1066 	/*
1067 	 * name (col 1)
1068 	 */
1069 	t = cname;
1070 	ctr = 0;
1071 	data.p_aliases = NULL;
1072 
1073 	do {
1074 		/*
1075 		 * don't clobber comment in canonical entry
1076 		 */
1077 		if (t != cname && strcasecmp(t, cname) == 0)
1078 			continue;
1079 		if (strcasecmp(t, ecol[0].ec_value.ec_value_val) == 0)
1080 			continue;
1081 
1082 		ecol[1].ec_value.ec_value_val = t;
1083 		ecol[1].ec_value.ec_value_len = strlen(t)+1;
1084 
1085 		ctr++;
1086 		alias = strdup(ecol[1].ec_value.ec_value_val);
1087 		if ((data.p_aliases = (char **)realloc(data.p_aliases,
1088 			ctr * sizeof (char **))) == NULL) {
1089 			(void) fprintf(stderr, gettext("out of memory\n"));
1090 			exit(1);
1091 		}
1092 		data.p_aliases[ctr-1] = alias;
1093 
1094 		/*
1095 		 * only put comment in canonical entry
1096 		 */
1097 		ecol[3].ec_value.ec_value_val = 0;
1098 		ecol[3].ec_value.ec_value_len = 0;
1099 
1100 	} while (t = strtok(NULL, " \t"));
1101 
1102 	/* End the list of all the aliases by NULL */
1103 	if ((data.p_aliases = (char **)realloc(data.p_aliases,
1104 		(ctr + 1) * sizeof (char **))) == NULL) {
1105 		(void) fprintf(stderr, gettext("out of memory\n"));
1106 		exit(1);
1107 	}
1108 	data.p_aliases[ctr] = NULL;
1109 
1110 	if (flags & F_VERBOSE)
1111 		(void) fprintf(stdout,
1112 		    gettext("Adding entry : %s\n"), data.p_name);
1113 
1114 	retval = (*cback)(&data, 0);
1115 
1116 	if (retval == LDAP_ALREADY_EXISTS) {
1117 		if (continue_onerror)
1118 			(void) fprintf(stderr,
1119 			gettext("Entry: %s - already Exists, skipping it.\n"),
1120 			data.p_name);
1121 		else {
1122 			rc = GENENT_CBERR;
1123 			(void) fprintf(stderr,
1124 				gettext("Entry: %s - already Exists\n"),
1125 				data.p_name);
1126 		}
1127 	} else if (retval)
1128 		rc = GENENT_CBERR;
1129 
1130 	free(data.p_name);
1131 	free(data.p_aliases);
1132 
1133 	return (rc);
1134 }
1135 
1136 
1137 static void
1138 dump_protocols(ns_ldap_result_t *res)
1139 {
1140 	ns_ldap_attr_t	*attrptr = NULL, *cn = NULL, *protocolnumber = NULL;
1141 	int		 i, j;
1142 	char		*name, *cp;
1143 
1144 	if (res == NULL || res->entry == NULL)
1145 		return;
1146 	for (i = 0; i < res->entry->attr_count; i++) {
1147 		attrptr = res->entry->attr_pair[i];
1148 		if (strcasecmp(attrptr->attrname, "cn") == 0)
1149 			cn = attrptr;
1150 		else if (strcasecmp(attrptr->attrname, "ipProtocolNumber")
1151 									== 0)
1152 			protocolnumber = attrptr;
1153 	}
1154 	/* sanity check */
1155 	if (cn == NULL || cn->attrvalue == NULL || cn->attrvalue[0] == NULL ||
1156 	    protocolnumber == NULL || protocolnumber->attrvalue == NULL ||
1157 	    protocolnumber->attrvalue[0] == NULL)
1158 		return;
1159 
1160 	if ((name = __s_api_get_canonical_name(res->entry, cn, 1)) == NULL)
1161 		return;
1162 
1163 	/* protocol name */
1164 	if (strlen(name) < 8)
1165 		(void) fprintf(stdout, "%s\t\t", name);
1166 	else
1167 		(void) fprintf(stdout, "%s\t", name);
1168 
1169 	/* protocol number */
1170 	(void) fprintf(stdout, "%-16s", protocolnumber->attrvalue[0]);
1171 
1172 	/* aliases */
1173 	for (j = 0; j < cn->value_count; j++) {
1174 		if (cn->attrvalue[j]) {
1175 			if (strcasecmp(name, cn->attrvalue[j]) == 0) {
1176 				if (cn->value_count > 1)
1177 					/* Do not replicate */
1178 					continue;
1179 				/*
1180 				 * Replicate name in uppercase as an aliase
1181 				 */
1182 				for (cp = cn->attrvalue[j]; *cp; cp++)
1183 					*cp = toupper(*cp);
1184 			}
1185 			(void) fprintf(stdout, "%s ", cn->attrvalue[j]);
1186 		}
1187 	}
1188 
1189 	/* end of line */
1190 	(void) fprintf(stdout, "\n");
1191 
1192 }
1193 
1194 
1195 
1196 
1197 
1198 /*
1199  * /etc/networks
1200  *
1201  */
1202 
1203 static int
1204 genent_networks(char *line, int (*cback)())
1205 {
1206 	char buf[BUFSIZ+1];
1207 	char *t;
1208 	entry_col ecol[4];
1209 	char *cname;
1210 
1211 	struct netent	data;
1212 	char *alias;
1213 	int ctr = 0;
1214 	int retval = 1;
1215 	int enet;
1216 	int rc = GENENT_OK;
1217 
1218 	/*
1219 	 * don't clobber our argument
1220 	 */
1221 	if (strlen(line) >= sizeof (buf)) {
1222 		(void) strcpy(parse_err_msg, "line too long");
1223 		return (GENENT_PARSEERR);
1224 	}
1225 	(void) strcpy(buf, line);
1226 
1227 	/*
1228 	 * clear column data
1229 	 */
1230 	(void) memset((char *)ecol, 0, sizeof (ecol));
1231 
1232 	/*
1233 	 * comment (col 3)
1234 	 */
1235 	t = strchr(buf, '#');
1236 	if (t) {
1237 		*t++ = 0;
1238 		ecol[3].ec_value.ec_value_val = t;
1239 		ecol[3].ec_value.ec_value_len = strlen(t)+1;
1240 	} else {
1241 		ecol[3].ec_value.ec_value_val = 0;
1242 		ecol[3].ec_value.ec_value_len = 0;
1243 	}
1244 
1245 	/*
1246 	 * cname(col 0)
1247 	 */
1248 	if ((t = strtok(buf, " \t")) == 0) {
1249 		(void) strcpy(parse_err_msg, "no number");
1250 		return (GENENT_PARSEERR);
1251 	}
1252 	ecol[0].ec_value.ec_value_val = t;
1253 	ecol[0].ec_value.ec_value_len = strlen(t)+1;
1254 	cname = t;
1255 
1256 	/*
1257 	 * number (col 2)
1258 	 */
1259 	if ((t = strtok(NULL, " \t")) == 0) {
1260 		(void) strcpy(parse_err_msg, "no number");
1261 		return (GENENT_PARSEERR);
1262 	}
1263 	ecol[2].ec_value.ec_value_val = t;
1264 	ecol[2].ec_value.ec_value_len = strlen(t)+1;
1265 
1266 
1267 	/*
1268 	 * build entry
1269 	 */
1270 
1271 	data.n_name = strdup(ecol[0].ec_value.ec_value_val);
1272 	/*
1273 	 * data.n_net is an unsigned field,
1274 	 * assign -1 to it, make no sense.
1275 	 * Use enet here to avoid lint warning.
1276 	 */
1277 	enet = encode_network(ecol[2].ec_value.ec_value_val);
1278 
1279 	if (enet == -1 && continue_onerror == 0) {
1280 		(void) fprintf(stderr, gettext("Invalid network number\n"));
1281 		if (continue_onerror == 0)
1282 			return (GENENT_CBERR);
1283 	} else
1284 		data.n_net = enet;
1285 
1286 	/*
1287 	 * name (col 1)
1288 	 */
1289 	t = cname;
1290 	data.n_aliases = NULL;
1291 
1292 	do {
1293 		/*
1294 		 * don't clobber comment in canonical entry
1295 		 */
1296 		if (t != cname && strcasecmp(t, cname) == 0)
1297 			continue;
1298 		if (strcasecmp(t, ecol[0].ec_value.ec_value_val) == 0)
1299 			continue;
1300 
1301 		ecol[1].ec_value.ec_value_val = t;
1302 		ecol[1].ec_value.ec_value_len = strlen(t)+1;
1303 
1304 		ctr++;
1305 		alias = strdup(ecol[1].ec_value.ec_value_val);
1306 		if ((data.n_aliases = (char **)realloc(data.n_aliases,
1307 			ctr * sizeof (char **))) == NULL) {
1308 			(void) fprintf(stderr, gettext("out of memory\n"));
1309 			exit(1);
1310 		}
1311 		data.n_aliases[ctr-1] = alias;
1312 
1313 		/*
1314 		 * only put comment in canonical entry
1315 		 */
1316 		ecol[3].ec_value.ec_value_val = 0;
1317 		ecol[3].ec_value.ec_value_len = 0;
1318 
1319 	} while (t = strtok(NULL, " \t"));
1320 
1321 	/* End the list of all the aliases by NULL */
1322 	if ((data.n_aliases = (char **)realloc(data.n_aliases,
1323 		(ctr + 1) * sizeof (char **))) == NULL) {
1324 		(void) fprintf(stderr, gettext("out of memory\n"));
1325 		exit(1);
1326 	}
1327 	data.n_aliases[ctr] = NULL;
1328 
1329 	if (flags & F_VERBOSE)
1330 		(void) fprintf(stdout,
1331 		    gettext("Adding entry : %s\n"), data.n_name);
1332 
1333 	retval = (*cback)(&data, 0);
1334 
1335 	if (retval == LDAP_ALREADY_EXISTS) {
1336 		if (continue_onerror)
1337 			(void) fprintf(stderr,
1338 			gettext("Entry: %s - already Exists, skipping it.\n"),
1339 			data.n_name);
1340 		else {
1341 			rc = GENENT_CBERR;
1342 			(void) fprintf(stderr,
1343 				gettext("Entry: %s - already Exists\n"),
1344 				data.n_name);
1345 		}
1346 	} else if (retval)
1347 		rc = GENENT_CBERR;
1348 
1349 	free(data.n_name);
1350 	free(data.n_aliases);
1351 
1352 	return (rc);
1353 }
1354 
1355 
1356 static void
1357 dump_networks(ns_ldap_result_t *res)
1358 {
1359 	ns_ldap_attr_t	*attrptr = NULL, *cn = NULL, *networknumber = NULL;
1360 	int		 i, j;
1361 	char		*name;
1362 
1363 	if (res == NULL || res->entry == NULL)
1364 		return;
1365 	for (i = 0; i < res->entry->attr_count; i++) {
1366 		attrptr = res->entry->attr_pair[i];
1367 		if (strcasecmp(attrptr->attrname, "cn") == 0)
1368 			cn = attrptr;
1369 		else if (strcasecmp(attrptr->attrname, "ipNetworkNumber")
1370 									== 0)
1371 			networknumber = attrptr;
1372 	}
1373 	/* sanity check */
1374 	if (cn == NULL || cn->attrvalue == NULL || cn->attrvalue[0] == NULL ||
1375 	    networknumber == NULL || networknumber->attrvalue == NULL ||
1376 	    networknumber->attrvalue[0] == NULL)
1377 		return;
1378 
1379 	/*
1380 	 * cn can be a MUST attribute(RFC 2307) or MAY attribute(2307bis).
1381 	 * If the canonical name can not be found (2307bis), use the 1st
1382 	 * value as the official name.
1383 	 */
1384 
1385 	/* network name */
1386 	if ((name = __s_api_get_canonical_name(res->entry, cn, 1)) == NULL)
1387 		name = cn->attrvalue[0];
1388 
1389 	if (strlen(name) < 8)
1390 		(void) fprintf(stdout, "%s\t\t", name);
1391 	else
1392 		(void) fprintf(stdout, "%s\t", name);
1393 
1394 	/* network number */
1395 	(void) fprintf(stdout, "%-16s", networknumber->attrvalue[0]);
1396 
1397 	/* aliases */
1398 	for (j = 0; j < cn->value_count; j++) {
1399 		if (cn->attrvalue[j]) {
1400 			if (strcasecmp(name, cn->attrvalue[j]) == 0)
1401 				/* skip name */
1402 				continue;
1403 			(void) fprintf(stdout, "%s ", cn->attrvalue[j]);
1404 		}
1405 	}
1406 
1407 	/* end of line */
1408 	(void) fprintf(stdout, "\n");
1409 
1410 }
1411 
1412 
1413 
1414 
1415 /*
1416  * /etc/services
1417  *
1418  */
1419 
1420 static int
1421 genent_services(char *line, int (*cback)())
1422 {
1423 	char buf[BUFSIZ+1];
1424 	char *t, *p;
1425 	entry_col ecol[5];
1426 	char *cname;
1427 
1428 	struct servent	data;
1429 	char *alias;
1430 	int ctr = 0;
1431 	int retval = 1;
1432 	int rc = GENENT_OK;
1433 
1434 	/*
1435 	 * don't clobber our argument
1436 	 */
1437 	if (strlen(line) >= sizeof (buf)) {
1438 		(void) strcpy(parse_err_msg, "line too long");
1439 		return (GENENT_PARSEERR);
1440 	}
1441 	(void) strcpy(buf, line);
1442 
1443 	/*
1444 	 * clear column data
1445 	 */
1446 	(void) memset((char *)ecol, 0, sizeof (ecol));
1447 
1448 	/*
1449 	 * comment (col 4)
1450 	 */
1451 	t = strchr(buf, '#');
1452 	if (t) {
1453 		*t++ = 0;
1454 		ecol[4].ec_value.ec_value_val = t;
1455 		ecol[4].ec_value.ec_value_len = strlen(t)+1;
1456 	} else {
1457 		ecol[4].ec_value.ec_value_val = 0;
1458 		ecol[4].ec_value.ec_value_len = 0;
1459 	}
1460 
1461 	/*
1462 	 * cname(col 0)
1463 	 */
1464 	if ((t = strtok(buf, " \t")) == 0) {
1465 		(void) strcpy(parse_err_msg, "no port");
1466 		return (GENENT_PARSEERR);
1467 	}
1468 	ecol[0].ec_value.ec_value_val = t;
1469 	ecol[0].ec_value.ec_value_len = strlen(t)+1;
1470 	cname = t;
1471 
1472 	/*
1473 	 * port (col 3)
1474 	 */
1475 	if ((t = strtok(NULL, " \t")) == 0) {
1476 		(void) strcpy(parse_err_msg, "no protocol");
1477 		return (GENENT_PARSEERR);
1478 	}
1479 	if ((p = strchr(t, '/')) == 0) {
1480 		(void) strcpy(parse_err_msg, "bad port/proto");
1481 		return (GENENT_PARSEERR);
1482 	}
1483 	*(p++) = 0;
1484 	ecol[3].ec_value.ec_value_val = t;
1485 	ecol[3].ec_value.ec_value_len = strlen(t)+1;
1486 
1487 	/*
1488 	 * proto (col 2)
1489 	 */
1490 	ecol[2].ec_value.ec_value_val = p;
1491 	ecol[2].ec_value.ec_value_len = strlen(p)+1;
1492 
1493 
1494 	/*
1495 	 * build entry
1496 	 */
1497 
1498 	data.s_name = strdup(ecol[0].ec_value.ec_value_val);
1499 	data.s_proto = strdup(ecol[2].ec_value.ec_value_val);
1500 
1501 	if (ecol[3].ec_value.ec_value_val != NULL &&
1502 		ecol[3].ec_value.ec_value_val[0] != '\0') {
1503 
1504 		data.s_port = ascii_to_int(ecol[3].ec_value.ec_value_val);
1505 		if (data.s_port == -1) {
1506 			(void) snprintf(parse_err_msg, sizeof (parse_err_msg),
1507 			    "invalid port number: %s",
1508 			    ecol[3].ec_value.ec_value_val);
1509 		return (GENENT_PARSEERR);
1510 		}
1511 	} else
1512 		data.s_port = -1;
1513 
1514 	/*
1515 	 * name (col 1)
1516 	 */
1517 	t = cname;
1518 	data.s_aliases = NULL;
1519 
1520 	do {
1521 		/*
1522 		 * don't clobber comment in canonical entry
1523 		 */
1524 		if (t != cname && strcasecmp(t, cname) == 0)
1525 			continue;
1526 		if (strcasecmp(t, ecol[0].ec_value.ec_value_val) == 0)
1527 			continue;
1528 
1529 		ecol[1].ec_value.ec_value_val = t;
1530 		ecol[1].ec_value.ec_value_len = strlen(t)+1;
1531 
1532 		ctr++;
1533 		alias = strdup(ecol[1].ec_value.ec_value_val);
1534 		if ((data.s_aliases = (char **)realloc(data.s_aliases,
1535 			ctr * sizeof (char **))) == NULL) {
1536 			(void) fprintf(stderr, gettext("out of memory\n"));
1537 			exit(1);
1538 		}
1539 		data.s_aliases[ctr-1] = alias;
1540 
1541 		/*
1542 		 * only put comment in canonical entry
1543 		 */
1544 		ecol[4].ec_value.ec_value_val = 0;
1545 		ecol[4].ec_value.ec_value_len = 0;
1546 
1547 	} while (t = strtok(NULL, " \t"));
1548 
1549 	/* End the list of all the aliases by NULL */
1550 	if ((data.s_aliases = (char **)realloc(data.s_aliases,
1551 		(ctr + 1) * sizeof (char **))) == NULL) {
1552 		(void) fprintf(stderr, gettext("out of memory\n"));
1553 		exit(1);
1554 	}
1555 	data.s_aliases[ctr] = NULL;
1556 
1557 	if (flags & F_VERBOSE)
1558 		(void) fprintf(stdout,
1559 		    gettext("Adding entry : %s\n"), line);
1560 
1561 	retval = (*cback)(&data, 0);
1562 
1563 	if (retval == LDAP_ALREADY_EXISTS) {
1564 		if (continue_onerror)
1565 			(void) fprintf(stderr, gettext(
1566 					"Entry: cn=%s+ipServiceProtocol=%s"
1567 					" already Exists, skipping it.\n"),
1568 					data.s_name, data.s_proto);
1569 		else {
1570 			rc = GENENT_CBERR;
1571 			(void) fprintf(stderr,
1572 				gettext("Entry: cn=%s+ipServiceProtocol=%s"
1573 					" - already Exists\n"),
1574 					data.s_name, data.s_proto);
1575 		}
1576 	} else if (retval)
1577 		rc = GENENT_CBERR;
1578 
1579 	free(data.s_name);
1580 	free(data.s_proto);
1581 	free(data.s_aliases);
1582 
1583 	return (rc);
1584 }
1585 
1586 
1587 
1588 static void
1589 dump_services(ns_ldap_result_t *res)
1590 {
1591 	ns_ldap_attr_t	*attrptr = NULL, *cn = NULL, *port = NULL;
1592 	ns_ldap_attr_t	*protocol = NULL;
1593 	int		i, j, len;
1594 	char		*name; /* service name */
1595 
1596 	/*
1597 	 * cn can have multiple values.(service name and its aliases)
1598 	 * In order to support RFC 2307, section 5.5, ipserviceprotocol  can
1599 	 * have multiple values too.
1600 	 * The output format should look like
1601 	 *
1602 	 * test		2345/udp mytest
1603 	 * test		2345/tcp mytest
1604 	 */
1605 	if (res == NULL || res->entry == NULL)
1606 		return;
1607 	for (i = 0; i < res->entry->attr_count; i++) {
1608 		attrptr = res->entry->attr_pair[i];
1609 		if (strcasecmp(attrptr->attrname, "cn") == 0)
1610 			cn = attrptr;
1611 		else if (strcasecmp(attrptr->attrname, "ipServicePort") == 0)
1612 			port = attrptr;
1613 		else if (strcasecmp(attrptr->attrname,
1614 					"ipServiceProtocol") == 0)
1615 			protocol = attrptr;
1616 	}
1617 	/* sanity check */
1618 	if (cn == NULL || cn->attrvalue == NULL || cn->attrvalue[0] == NULL ||
1619 	    port == NULL || port->attrvalue == NULL ||
1620 	    port->attrvalue[0] == NULL || protocol == NULL ||
1621 	    protocol->attrvalue == NULL || protocol->attrvalue[0] == NULL)
1622 		return;
1623 
1624 	if ((name = __s_api_get_canonical_name(res->entry, cn, 1)) == NULL)
1625 		return;
1626 	for (i = 0; i < protocol->value_count; i++) {
1627 		if (protocol->attrvalue[i] == NULL)
1628 			return;
1629 		/* service name */
1630 		(void) fprintf(stdout, "%-16s", name);
1631 
1632 		/* port & protocol */
1633 		(void) fprintf(stdout, "%s/%s%n", port->attrvalue[0],
1634 				protocol->attrvalue[i], &len);
1635 
1636 		if (len < 8)
1637 			(void) fprintf(stdout, "\t\t");
1638 		else
1639 			(void) fprintf(stdout, "\t");
1640 
1641 		/* aliases */
1642 		for (j = 0; j < cn->value_count; j++) {
1643 			if (cn->attrvalue[j]) {
1644 				if (strcasecmp(name, cn->attrvalue[j]) == 0)
1645 					/* skip service name */
1646 					continue;
1647 				(void) fprintf(stdout, "%s ", cn->attrvalue[j]);
1648 			}
1649 		}
1650 
1651 		/* end of line */
1652 		(void) fprintf(stdout, "\n");
1653 	}
1654 }
1655 
1656 
1657 /*
1658  * /etc/group
1659  */
1660 
1661 static int
1662 genent_group(char *line, int (*cback)())
1663 {
1664 	char buf[BIGBUF+1];
1665 	char *s, *t;
1666 	entry_col ecol[5];
1667 
1668 	struct group	data;
1669 	int ctr = 0;
1670 	int retval = 1;
1671 	int rc = GENENT_OK;
1672 
1673 	/*
1674 	 * don't clobber our argument
1675 	 */
1676 	if (strlen(line) >= sizeof (buf)) {
1677 		(void) strcpy(parse_err_msg, "line too long");
1678 		return (GENENT_PARSEERR);
1679 	}
1680 	(void) strcpy(buf, line);
1681 	t = buf;
1682 
1683 	/* ignore empty entries */
1684 	if (*t == '\0')
1685 		return (GENENT_OK);
1686 
1687 	/*
1688 	 * clear column data
1689 	 */
1690 	(void) memset((char *)ecol, 0, sizeof (ecol));
1691 
1692 	/*
1693 	 * name (col 0)
1694 	 */
1695 	if ((s = strchr(t, ':')) == 0) {
1696 		(void) strcpy(parse_err_msg, "no passwd");
1697 		return (GENENT_PARSEERR);
1698 	}
1699 	*s++ = 0;
1700 	ecol[0].ec_value.ec_value_val = t;
1701 	ecol[0].ec_value.ec_value_len = strlen(t)+1;
1702 	t = s;
1703 
1704 	/*
1705 	 * passwd (col 1)
1706 	 */
1707 	if ((s = strchr(t, ':')) == 0) {
1708 		(void) strcpy(parse_err_msg, "no gid");
1709 		return (GENENT_PARSEERR);
1710 	}
1711 	*s++ = 0;
1712 	ecol[1].ec_value.ec_value_val = t;
1713 	ecol[1].ec_value.ec_value_len = strlen(t)+1;
1714 	t = s;
1715 
1716 
1717 	/*
1718 	 * gid (col 2)
1719 	 */
1720 	if ((s = strchr(t, ':')) == 0 || s == t) {
1721 		(void) strcpy(parse_err_msg, "no members");
1722 		return (GENENT_PARSEERR);
1723 	}
1724 	*s++ = 0;
1725 	ecol[2].ec_value.ec_value_val = t;
1726 	ecol[2].ec_value.ec_value_len = strlen(t)+1;
1727 	t = s;
1728 
1729 	/*
1730 	 * members (col 3)
1731 	 */
1732 	ecol[3].ec_value.ec_value_val = t;
1733 	ecol[3].ec_value.ec_value_len = strlen(t)+1;
1734 
1735 
1736 	/*
1737 	 * build entry
1738 	 */
1739 	data.gr_name = strdup(ecol[0].ec_value.ec_value_val);
1740 	data.gr_passwd = strdup(ecol[1].ec_value.ec_value_val);
1741 	if (ecol[2].ec_value.ec_value_val != NULL &&
1742 		ecol[2].ec_value.ec_value_val[0] != '\0') {
1743 
1744 		data.gr_gid = ascii_to_int(ecol[2].ec_value.ec_value_val);
1745 		if (data.gr_gid == -1) {
1746 			(void) snprintf(parse_err_msg, sizeof (parse_err_msg),
1747 			    "invalid group id: %s",
1748 			    ecol[2].ec_value.ec_value_val);
1749 		return (GENENT_PARSEERR);
1750 		}
1751 	} else
1752 		data.gr_gid = -1;
1753 
1754 	data.gr_mem = NULL;
1755 
1756 	/* Compute maximum amount of members */
1757 	s = t;
1758 	while (s = strchr(s, ',')) {
1759 		s++;
1760 		ctr++;
1761 	}
1762 
1763 	/* Allocate memory for all members */
1764 	data.gr_mem = calloc(ctr + 2, sizeof (char **));
1765 	if (data.gr_mem == NULL) {
1766 		(void) fprintf(stderr, gettext("out of memory\n"));
1767 		exit(1);
1768 	}
1769 
1770 	ctr = 0;
1771 	while (s = strchr(t, ',')) {
1772 
1773 		*s++ = 0;
1774 		ecol[3].ec_value.ec_value_val = t;
1775 		t = s;
1776 		/* Send to server only non empty member names */
1777 		if (strlen(ecol[3].ec_value.ec_value_val) != 0)
1778 			data.gr_mem[ctr++] = ecol[3].ec_value.ec_value_val;
1779 	}
1780 
1781 	/* Send to server only non empty member names */
1782 	if (strlen(t) != 0)
1783 		data.gr_mem[ctr++] = t;
1784 
1785 	/* Array of members completed, finished by NULL, see calloc() */
1786 
1787 	if (flags & F_VERBOSE)
1788 		(void) fprintf(stdout,
1789 		    gettext("Adding entry : %s\n"), data.gr_name);
1790 
1791 	retval = (*cback)(&data, 0);
1792 
1793 	if (retval == LDAP_ALREADY_EXISTS) {
1794 		if (continue_onerror)
1795 			(void) fprintf(stderr,
1796 			gettext("Entry: %s - already Exists, skipping it.\n"),
1797 			data.gr_name);
1798 		else {
1799 			rc = GENENT_CBERR;
1800 			(void) fprintf(stderr,
1801 				gettext("Entry: %s - already Exists\n"),
1802 				data.gr_name);
1803 		}
1804 	} else if (retval)
1805 		rc = GENENT_CBERR;
1806 
1807 	free(data.gr_name);
1808 	free(data.gr_passwd);
1809 	free(data.gr_mem);
1810 
1811 	return (rc);
1812 }
1813 
1814 static void
1815 dump_group(ns_ldap_result_t *res)
1816 {
1817 	char    **value = NULL;
1818 	char	pnam[256];
1819 	int	attr_count = 0;
1820 
1821 	value = __ns_ldap_getAttr(res->entry, "cn");
1822 	if (value && value[0])
1823 		(void) fprintf(stdout, "%s:", value[0]);
1824 	value = __ns_ldap_getAttr(res->entry, "userPassword");
1825 	if (value == NULL || value[0] == NULL)
1826 		(void) fprintf(stdout, "*:");
1827 	else {
1828 		(void) strcpy(pnam, value[0]);
1829 		if (strncasecmp(value[0], "{crypt}", 7) == 0)
1830 			(void) fprintf(stdout, "%s:", (pnam+7));
1831 		else
1832 			(void) fprintf(stdout, "*:");
1833 	}
1834 	value = __ns_ldap_getAttr(res->entry, "gidNumber");
1835 	if (value && value[0])
1836 		(void) fprintf(stdout, "%s:", value[0]);
1837 
1838 	value = __ns_ldap_getAttr(res->entry, "memberUid");
1839 	if (value != NULL && value[0] != NULL) {
1840 		while (value[attr_count] != NULL) {
1841 			if (value[attr_count+1] == NULL)
1842 				(void) fprintf(stdout, "%s", value[attr_count]);
1843 			else
1844 				(void) fprintf(stdout, "%s,",
1845 					value[attr_count]);
1846 			attr_count++;
1847 		}
1848 		(void) fprintf(stdout, "\n");
1849 	}
1850 	else
1851 		(void) fprintf(stdout, "\n");
1852 }
1853 
1854 
1855 
1856 
1857 
1858 /*
1859  * /etc/ethers
1860  */
1861 
1862 static int
1863 genent_ethers(char *line, int (*cback)())
1864 {
1865 	char buf[BUFSIZ+1];
1866 	char *t;
1867 	entry_col ecol[3];
1868 	int retval = 1;
1869 	struct _ns_ethers	data;
1870 	int rc = GENENT_OK;
1871 
1872 	/*
1873 	 * don't clobber our argument
1874 	 */
1875 	if (strlen(line) >= sizeof (buf)) {
1876 		(void) strcpy(parse_err_msg, "line too long");
1877 		return (GENENT_PARSEERR);
1878 	}
1879 	(void) strcpy(buf, line);
1880 
1881 	/*
1882 	 * clear column data
1883 	 */
1884 	(void) memset((char *)ecol, 0, sizeof (ecol));
1885 
1886 	/*
1887 	 * comment (col 2)
1888 	 */
1889 	t = strchr(buf, '#');
1890 	if (t) {
1891 		*t++ = 0;
1892 		ecol[2].ec_value.ec_value_val = t;
1893 		ecol[2].ec_value.ec_value_len = strlen(t)+1;
1894 	} else {
1895 		ecol[2].ec_value.ec_value_val = 0;
1896 		ecol[2].ec_value.ec_value_len = 0;
1897 	}
1898 
1899 	/*
1900 	 * addr(col 0)
1901 	 */
1902 	if ((t = strtok(buf, " \t")) == 0) {
1903 		(void) strcpy(parse_err_msg, "no name");
1904 		return (GENENT_PARSEERR);
1905 	}
1906 	ecol[0].ec_value.ec_value_val = t;
1907 	ecol[0].ec_value.ec_value_len = strlen(t)+1;
1908 
1909 	/*
1910 	 * name(col 1)
1911 	 */
1912 	if ((t = strtok(NULL, " \t")) == 0) {
1913 		(void) strcpy(parse_err_msg, "no white space allowed in name");
1914 		return (GENENT_PARSEERR);
1915 	}
1916 	ecol[1].ec_value.ec_value_val = t;
1917 	ecol[1].ec_value.ec_value_len = strlen(t)+1;
1918 
1919 
1920 	/*
1921 	 * build entry
1922 	 */
1923 
1924 	data.ether = strdup(ecol[0].ec_value.ec_value_val);
1925 	data.name  = strdup(ecol[1].ec_value.ec_value_val);
1926 
1927 
1928 	if (flags & F_VERBOSE)
1929 		(void) fprintf(stdout,
1930 		    gettext("Adding entry : %s\n"), data.name);
1931 
1932 	retval = (*cback)(&data, 0);
1933 
1934 	if (retval == LDAP_ALREADY_EXISTS) {
1935 		if (continue_onerror)
1936 			(void) fprintf(stderr,
1937 			gettext("Entry: %s - already Exists, skipping it.\n"),
1938 			data.name);
1939 		else {
1940 			rc = GENENT_CBERR;
1941 			(void) fprintf(stderr,
1942 				gettext("Entry: %s - already Exists\n"),
1943 				data.name);
1944 		}
1945 	} else if (retval)
1946 		rc = GENENT_CBERR;
1947 
1948 	free(data.ether);
1949 	free(data.name);
1950 
1951 	return (rc);
1952 }
1953 
1954 
1955 static void
1956 dump_ethers(ns_ldap_result_t *res)
1957 {
1958 	char	**value = NULL;
1959 
1960 	value = __ns_ldap_getAttr(res->entry, "macAddress");
1961 	if (value && value[0])
1962 		(void) fprintf(stdout, "%s", value[0]);
1963 	else
1964 		return;
1965 	value = __ns_ldap_getAttr(res->entry, "cn");
1966 	if (value && value[0])
1967 		(void) fprintf(stdout, "	%s\n", value[0]);
1968 }
1969 
1970 static int
1971 genent_aliases(char *line, int (*cback)())
1972 {
1973 	char buf[BUFSIZ+1];
1974 	char *t, *aliases;
1975 	char *cname;
1976 	int ctr = 0;
1977 	int retval = 1;
1978 	int i;
1979 
1980 	struct _ns_alias data;
1981 	char *alias;
1982 	int rc = GENENT_OK;
1983 
1984 	/*
1985 	 * don't clobber our argument
1986 	 */
1987 	if (strlen(line) >= sizeof (buf)) {
1988 		(void) strcpy(parse_err_msg, "line too long");
1989 		return (GENENT_PARSEERR);
1990 	}
1991 
1992 	(void) strcpy(buf, line);
1993 
1994 	if ((t = strchr(buf, ':')) == 0) {
1995 		(void) strcpy(parse_err_msg, "no alias name");
1996 		return (GENENT_PARSEERR);
1997 	}
1998 
1999 	t[0] = '\0';
2000 	if (++t == '\0') {
2001 		(void) strcpy(parse_err_msg, "no alias value");
2002 		return (GENENT_PARSEERR);
2003 	}
2004 
2005 	cname = buf;
2006 	aliases = t;
2007 
2008 	/* build entry */
2009 	data.alias = strdup(cname);
2010 	if (!data.alias) {
2011 		(void) fprintf(stderr, gettext("out of memory\n"));
2012 		exit(1);
2013 	}
2014 
2015 	data.member = NULL;
2016 	t = strtok(aliases, ",");
2017 	do {
2018 		ctr++;
2019 		while (t[0] == ' ')
2020 			t++;
2021 		alias = strdup(t);
2022 		if ((alias == NULL) ||
2023 			((data.member = (char **)realloc(data.member,
2024 			(ctr + 1) * sizeof (char **))) == NULL)) {
2025 			(void) fprintf(stderr, gettext("out of memory\n"));
2026 			exit(1);
2027 		}
2028 		data.member[ctr-1] = alias;
2029 
2030 	} while (t = strtok(NULL, ","));
2031 
2032 	data.member[ctr] = NULL;
2033 
2034 	if (flags & F_VERBOSE)
2035 		(void) fprintf(stdout,
2036 		    gettext("Adding entry : %s\n"), data.alias);
2037 
2038 	retval = (*cback)(&data, 0);
2039 
2040 	if (retval == LDAP_ALREADY_EXISTS) {
2041 		if (continue_onerror)
2042 			(void) fprintf(stderr,
2043 			gettext("Entry: %s - already Exists, skipping it.\n"),
2044 			data.alias);
2045 		else {
2046 			rc = GENENT_CBERR;
2047 			(void) fprintf(stderr,
2048 				gettext("Entry: %s - already Exists\n"),
2049 				data.alias);
2050 		}
2051 	} else if (retval)
2052 		rc = GENENT_CBERR;
2053 
2054 	free(data.alias);
2055 	i = 0;
2056 	while (data.member[i])
2057 		free(data.member[i++]);
2058 	free(data.member);
2059 
2060 	return (rc);
2061 }
2062 
2063 
2064 static void
2065 dump_aliases(ns_ldap_result_t *res)
2066 {
2067 
2068 	char	**value = NULL;
2069 	int 		attr_count = 0;
2070 
2071 	value = __ns_ldap_getAttr(res->entry, "mail");
2072 	if (value && value[0])
2073 		(void) fprintf(stdout, "%s:", value[0]);
2074 	value = __ns_ldap_getAttr(res->entry, "mgrpRFC822MailMember");
2075 	if (value != NULL)
2076 		while (value[attr_count] != NULL) {
2077 			(void) fprintf(stdout, "%s,", value[attr_count]);
2078 			attr_count++;
2079 		}
2080 	(void) fprintf(stdout, "\n");
2081 
2082 }
2083 
2084 /*
2085  * /etc/publickey
2086  */
2087 
2088 static int
2089 genent_publickey(char *line, int (*cback)())
2090 {
2091 	char buf[BUFSIZ+1], tmpbuf[BUFSIZ+1], cname[BUFSIZ+1];
2092 	char *t, *p, *tmppubkey, *tmpprivkey;
2093 	entry_col ecol[3];
2094 	int buflen, uid, retval = 1;
2095 	struct passwd *pwd;
2096 	char auth_type[BUFSIZ+1];
2097 	keylen_t keylen;
2098 	algtype_t algtype;
2099 	struct _ns_pubkey data;
2100 	struct hostent *hp;
2101 	struct in_addr in;
2102 
2103 	/*
2104 	 * don't clobber our argument
2105 	 */
2106 	if (strlen(line) >= sizeof (buf)) {
2107 		(void) strcpy(parse_err_msg, "line too long");
2108 		return (GENENT_PARSEERR);
2109 	}
2110 	(void) strcpy(buf, line);
2111 
2112 	/*
2113 	 * clear column data
2114 	 */
2115 	(void) memset((char *)ecol, 0, sizeof (ecol));
2116 
2117 	if ((t = strtok(buf, " \t")) == 0) {
2118 		(void) strcpy(parse_err_msg, "no cname");
2119 		return (GENENT_PARSEERR);
2120 	}
2121 
2122 	/*
2123 	 * Special case:  /etc/publickey usually has an entry
2124 	 * for principal "nobody".  We skip it.
2125 	 */
2126 	if (strcmp(t, "nobody") == 0)
2127 		return (GENENT_OK);
2128 
2129 	/*
2130 	 * cname (col 0)
2131 	 */
2132 	if (strncmp(t, "unix.", 5)) {
2133 		(void) strcpy(parse_err_msg, "bad cname");
2134 		return (GENENT_PARSEERR);
2135 	}
2136 	(void) strcpy(tmpbuf, &(t[5]));
2137 	if ((p = strchr(tmpbuf, '@')) == 0) {
2138 		(void) strcpy(parse_err_msg, "bad cname");
2139 		return (GENENT_PARSEERR);
2140 	}
2141 	*(p++) = 0;
2142 	if (isdigit(*tmpbuf)) {
2143 
2144 		uid = atoi(tmpbuf);
2145 		/*
2146 		 * don't generate entries for uids without passwd entries
2147 		 */
2148 		if ((pwd = getpwuid(uid)) == 0) {
2149 			(void) fprintf(stderr,
2150 			gettext("can't map uid %d to username, skipping\n"),
2151 				uid);
2152 			return (GENENT_OK);
2153 		}
2154 		(void) strcpy(cname, pwd->pw_name);
2155 		data.hostcred = NS_HOSTCRED_FALSE;
2156 	} else {
2157 		if ((hp = gethostbyname(tmpbuf)) == 0) {
2158 			(void) fprintf(stderr,
2159 		gettext("can't map hostname %s to hostaddress, skipping\n"),
2160 			tmpbuf);
2161 			return (GENENT_OK);
2162 		}
2163 		(void) memcpy((char *)&in.s_addr, hp->h_addr_list[0],
2164 		    sizeof (in));
2165 		data.hostcred = NS_HOSTCRED_TRUE;
2166 		(void) snprintf(cname, sizeof (cname),
2167 		    "%s+ipHostNumber=%s", tmpbuf, inet_ntoa(in));
2168 	}
2169 
2170 	ecol[0].ec_value.ec_value_val = cname;
2171 	ecol[0].ec_value.ec_value_len = strlen(cname)+1;
2172 
2173 	/*
2174 	 * public_data (col 1)
2175 	 */
2176 	if ((t = strtok(NULL, " \t")) == 0) {
2177 		(void) strcpy(parse_err_msg, "no private_data");
2178 		return (GENENT_PARSEERR);
2179 	}
2180 	if ((p = strchr(t, ':')) == 0) {
2181 		(void) strcpy(parse_err_msg, "bad public_data");
2182 		return (GENENT_PARSEERR);
2183 	}
2184 	*(p++) = 0;
2185 	ecol[1].ec_value.ec_value_val = t;
2186 	ecol[1].ec_value.ec_value_len = strlen(t)+1;
2187 	keylen = (strlen(t) / 2) * 8;
2188 
2189 	/*
2190 	 * private_data (col 2) and algtype extraction
2191 	 */
2192 	if (*p == ':')
2193 		p++;
2194 	t = p;
2195 	if (!(t = strchr(t, ':'))) {
2196 		(void) fprintf(stderr,
2197 		gettext("WARNING: No algorithm type data found "
2198 			"in publickey file, assuming 0\n"));
2199 		algtype = 0;
2200 	} else {
2201 		*t = '\0';
2202 		t++;
2203 		algtype = atoi(t);
2204 	}
2205 	ecol[2].ec_value.ec_value_val = p;
2206 	ecol[2].ec_value.ec_value_len = strlen(p)+1;
2207 
2208 	/*
2209 	 * auth_type (col 1)
2210 	 */
2211 	if (!(__nis_keyalg2authtype(keylen, algtype, auth_type,
2212 						MECH_MAXATNAME))) {
2213 		(void) fprintf(stderr,
2214 		gettext("Could not convert algorithm type to "
2215 			"corresponding auth type string\n"));
2216 		return (GENENT_ERR);
2217 	}
2218 
2219 	/*
2220 	 * build entry
2221 	 */
2222 	data.name = strdup(ecol[0].ec_value.ec_value_val);
2223 	if (data.name == NULL) {
2224 		(void) fprintf(stderr, gettext("out of memory\n"));
2225 		exit(1);
2226 	}
2227 
2228 	buflen = sizeof (auth_type) + strlen(ecol[1].ec_value.ec_value_val) + 3;
2229 	if ((tmppubkey = (char *)malloc(buflen)) == NULL) {
2230 		(void) fprintf(stderr, gettext("out of memory\n"));
2231 		exit(1);
2232 	}
2233 	(void) snprintf(tmppubkey, buflen, "{%s}%s", auth_type,
2234 	    ecol[1].ec_value.ec_value_val);
2235 	data.pubkey = tmppubkey;
2236 
2237 	buflen = sizeof (auth_type) + strlen(ecol[2].ec_value.ec_value_val) + 3;
2238 	if ((tmpprivkey = (char *)malloc(buflen)) == NULL) {
2239 		(void) fprintf(stderr, gettext("out of memory\n"));
2240 		exit(1);
2241 	}
2242 
2243 	(void) snprintf(tmpprivkey, buflen, "{%s}%s", auth_type,
2244 	    ecol[2].ec_value.ec_value_val);
2245 	data.privkey = tmpprivkey;
2246 
2247 	retval = (*cback)(&data, 1);
2248 
2249 	if ((retval != NS_LDAP_SUCCESS) && (continue_onerror == 0))
2250 		return (GENENT_CBERR);
2251 	else {
2252 		free(data.name);
2253 		free(data.pubkey);
2254 		free(data.privkey);
2255 		return (GENENT_OK);
2256 	}
2257 }
2258 
2259 static void
2260 dump_publickey(ns_ldap_result_t *res, char *container)
2261 {
2262 	char	**value = NULL;
2263 	char	buf[BUFSIZ];
2264 	char	domainname[BUFSIZ];
2265 	char	*pubptr, *prvptr;
2266 
2267 	if (res == NULL)
2268 		return;
2269 
2270 	if (sysinfo(SI_SRPC_DOMAIN, domainname, BUFSIZ) < 0) {
2271 		(void) fprintf(stderr,
2272 			gettext("could not obtain domainname\n"));
2273 		exit(1);
2274 	}
2275 
2276 	/*
2277 	 * Retrieve all the attributes, but don't print
2278 	 * until we have all the required ones.
2279 	 */
2280 
2281 	if (strcmp(container, "passwd") == 0)
2282 		value = __ns_ldap_getAttr(res->entry, "uidNumber");
2283 	else
2284 		value = __ns_ldap_getAttr(res->entry, "cn");
2285 
2286 	if (value && value[0])
2287 		(void) snprintf(buf, sizeof (buf), "unix.%s@%s",
2288 		    value[0], domainname);
2289 	else
2290 		return;
2291 
2292 	value = __ns_ldap_getAttr(res->entry, "nisPublickey");
2293 	if (value != NULL && value[0] != NULL) {
2294 		if ((pubptr = strchr(value[0], '}')) == NULL)
2295 			return;
2296 	}
2297 
2298 	value = __ns_ldap_getAttr(res->entry, "nisSecretkey");
2299 	if (value != NULL && value[0] != NULL)
2300 		if ((prvptr = strchr(value[0], '}')) == NULL)
2301 			return;
2302 
2303 	/* print the attributes, algorithm type is always 0 */
2304 	(void) fprintf(stdout, "%s	%s:%s:0\n", buf, ++pubptr, ++prvptr);
2305 }
2306 
2307 
2308 
2309 /*
2310  * /etc/netmasks
2311  */
2312 
2313 static int
2314 genent_netmasks(char *line, int (*cback)())
2315 {
2316 	char buf[BUFSIZ+1];
2317 	char *t;
2318 	entry_col ecol[3];
2319 
2320 	struct _ns_netmasks data;
2321 
2322 
2323 	/*
2324 	 * don't clobber our argument
2325 	 */
2326 	if (strlen(line) >= sizeof (buf)) {
2327 		(void) strcpy(parse_err_msg, "line too long");
2328 		return (GENENT_PARSEERR);
2329 	}
2330 	(void) strcpy(buf, line);
2331 
2332 	/*
2333 	 * clear column data
2334 	 */
2335 	(void) memset((char *)ecol, 0, sizeof (ecol));
2336 
2337 	/*
2338 	 * comment (col 2)
2339 	 */
2340 	t = strchr(buf, '#');
2341 	if (t) {
2342 		*t++ = 0;
2343 		ecol[2].ec_value.ec_value_val = t;
2344 		ecol[2].ec_value.ec_value_len = strlen(t)+1;
2345 	} else {
2346 		ecol[2].ec_value.ec_value_val = 0;
2347 		ecol[2].ec_value.ec_value_len = 0;
2348 	}
2349 
2350 	/*
2351 	 * addr(col 0)
2352 	 */
2353 	if ((t = strtok(buf, " \t")) == 0) {
2354 		(void) strcpy(parse_err_msg, "no mask");
2355 		return (GENENT_PARSEERR);
2356 	}
2357 	ecol[0].ec_value.ec_value_val = t;
2358 	ecol[0].ec_value.ec_value_len = strlen(t)+1;
2359 
2360 	/*
2361 	 * mask (col 1)
2362 	 */
2363 	if ((t = strtok(NULL, " \t")) == 0) {
2364 		(void) strcpy(parse_err_msg, "no mask");
2365 		return (GENENT_PARSEERR);
2366 	}
2367 	ecol[1].ec_value.ec_value_val = t;
2368 	ecol[1].ec_value.ec_value_len = strlen(t)+1;
2369 
2370 	/* build entry */
2371 	data.netnumber = ecol[0].ec_value.ec_value_val;
2372 	data.netmask = ecol[1].ec_value.ec_value_val;
2373 
2374 	if (flags & F_VERBOSE)
2375 		(void) fprintf(stdout,
2376 		    gettext("Adding entry : %s\n"), data.netnumber);
2377 
2378 	if ((*cback)(&data, 1) && continue_onerror == 0)
2379 		return (GENENT_CBERR);
2380 
2381 	return (GENENT_OK);
2382 }
2383 
2384 static void
2385 dump_netmasks(ns_ldap_result_t *res)
2386 {
2387 	char	**value = NULL;
2388 
2389 	value = __ns_ldap_getAttr(res->entry, "ipNetworkNumber");
2390 	if (value && value[0])
2391 		(void) fprintf(stdout, "%s", value[0]);
2392 	value = __ns_ldap_getAttr(res->entry, "ipNetmaskNumber");
2393 	if (value && value[0])
2394 		(void) fprintf(stdout, "	%s\n", value[0]);
2395 }
2396 
2397 
2398 /*
2399  * /etc/netgroup
2400  * column data format is:
2401  *    col 0: netgroup name (or cname)
2402  *    col 1: netgroup member, if this is a triplet
2403  *    col 2: netgroup member, if not a triplet
2404  *    col 3: comment
2405  */
2406 
2407 static int
2408 genent_netgroup(char *line, int (*cback)())
2409 {
2410 	char buf[BIGBUF+1];    /* netgroup entries tend to be big */
2411 	char *t;
2412 	char *cname = NULL;
2413 	entry_col ecol[4];
2414 	char *netg_tmp = NULL, *triplet_tmp = NULL;
2415 	int netgcount = 0, tripletcount = 0, retval = 1, i;
2416 	struct _ns_netgroups data;
2417 	int rc = GENENT_OK;
2418 
2419 	/* don't clobber our argument */
2420 	if (strlen(line) >= sizeof (buf)) {
2421 		(void) strcpy(parse_err_msg, "line too long");
2422 		return (GENENT_PARSEERR);
2423 	}
2424 	(void) strcpy(buf, line);
2425 
2426 	/* clear column data */
2427 	(void) memset((char *)ecol, 0, sizeof (ecol));
2428 
2429 	/*
2430 	 * process 1st minimal entry, to validate that there is no
2431 	 * parsing error.
2432 	 * start with comment(col 3)
2433 	 */
2434 	t = strchr(buf, '#');
2435 	if (t) {
2436 		*t++ = 0;
2437 		ecol[3].ec_value.ec_value_val = t;
2438 		ecol[3].ec_value.ec_value_len = strlen(t)+1;
2439 	} else {
2440 		ecol[3].ec_value.ec_value_val = "";
2441 		ecol[3].ec_value.ec_value_len = 0;
2442 	}
2443 
2444 	ecol[1].ec_value.ec_value_val = NULL;
2445 	ecol[2].ec_value.ec_value_val = NULL;
2446 
2447 	/* cname (col 0) */
2448 	if ((t = strtok(buf, " \t")) == 0) {
2449 		(void) strcpy(parse_err_msg, "no cname");
2450 		return (GENENT_PARSEERR);
2451 	}
2452 
2453 	ecol[0].ec_value.ec_value_val = t;
2454 	ecol[0].ec_value.ec_value_len = strlen(t)+1;
2455 	cname = t;
2456 
2457 	/* addr(col 1 and 2) */
2458 	if ((t = strtok(NULL, " \t")) == 0) {
2459 		(void) strcpy(parse_err_msg, "no members for netgroup");
2460 		return (GENENT_PARSEERR);
2461 	}
2462 
2463 	if (*t == '(') {
2464 		/* if token starts with '(' it must be a valid triplet */
2465 		if (is_triplet(t)) {
2466 			ecol[1].ec_value.ec_value_val = t;
2467 			ecol[1].ec_value.ec_value_len = strlen(t)+1;
2468 		} else {
2469 			(void) strcpy(parse_err_msg, "invalid triplet");
2470 			return (GENENT_PARSEERR);
2471 		}
2472 	} else {
2473 		ecol[2].ec_value.ec_value_val = t;
2474 		ecol[2].ec_value.ec_value_len = strlen(t)+1;
2475 	}
2476 
2477 	/*
2478 	 * now build entry.
2479 	 * start by clearing entry data
2480 	 */
2481 	(void) memset((struct _ns_netgroups *)&data, 0, sizeof (data));
2482 
2483 	data.name = strdup(ecol[0].ec_value.ec_value_val);
2484 
2485 	if (ecol[1].ec_value.ec_value_val != NULL) {
2486 		if ((data.triplet = calloc(1, sizeof (char **))) == NULL) {
2487 				(void) fprintf(stderr,
2488 					gettext("out of memory\n"));
2489 				exit(1);
2490 		}
2491 		data.triplet[tripletcount++] =
2492 		    strdup(ecol[1].ec_value.ec_value_val);
2493 	} else if (ecol[2].ec_value.ec_value_val != NULL) {
2494 			if ((data.netgroup = calloc(1, sizeof (char **)))
2495 			    == NULL) {
2496 					(void) fprintf(stderr,
2497 				    gettext("out of memory\n"));
2498 					exit(1);
2499 			}
2500 			data.netgroup[netgcount++] =
2501 			    strdup(ecol[2].ec_value.ec_value_val);
2502 	}
2503 
2504 	/*
2505 	 * we now have a valid entry (at least 1 netgroup name and
2506 	 * 1 netgroup member), proceed with the rest of the line
2507 	 */
2508 	while (rc == GENENT_OK && (t = strtok(NULL, " \t"))) {
2509 
2510 		/* if next token is equal to netgroup name, ignore */
2511 		if (t != cname && strcasecmp(t, cname) == 0)
2512 			continue;
2513 		if (strcasecmp(t, ecol[0].ec_value.ec_value_val) == 0)
2514 			continue;
2515 
2516 		if (*t == '(') {
2517 			if (is_triplet(t)) {
2518 				/* skip a triplet if it is added already */
2519 				for (i = 0; i < tripletcount &&
2520 					strcmp(t, data.triplet[i]); i++)
2521 					;
2522 				if (i < tripletcount)
2523 					continue;
2524 
2525 				tripletcount++;
2526 				triplet_tmp = strdup(t);
2527 				if ((data.triplet = (char **)realloc(
2528 					data.triplet,
2529 					tripletcount * sizeof (char **)))
2530 					== NULL) {
2531 					(void) fprintf(stderr,
2532 						gettext("out of memory\n"));
2533 					exit(1);
2534 				}
2535 				data.triplet[tripletcount-1] = triplet_tmp;
2536 			} else {
2537 				(void) strcpy(parse_err_msg, "invalid triplet");
2538 				rc = GENENT_PARSEERR;
2539 			}
2540 		} else {
2541 			/* skip a netgroup if it is added already */
2542 			for (i = 0; i < netgcount &&
2543 				strcmp(t, data.netgroup[i]); i++)
2544 				;
2545 			if (i < netgcount)
2546 				continue;
2547 
2548 			netgcount++;
2549 			netg_tmp = strdup(t);
2550 			if ((data.netgroup = (char **)realloc(data.netgroup,
2551 				netgcount * sizeof (char **))) == NULL) {
2552 				(void) fprintf(stderr,
2553 				gettext("out of memory\n"));
2554 				exit(1);
2555 			}
2556 			data.netgroup[netgcount-1] = netg_tmp;
2557 		}
2558 	}
2559 
2560 	/* End the list with NULL */
2561 	if ((data.triplet = (char **)realloc(data.triplet,
2562 		(tripletcount + 1) * sizeof (char **))) == NULL) {
2563 		(void) fprintf(stderr, gettext("out of memory\n"));
2564 		exit(1);
2565 	}
2566 	data.triplet[tripletcount] = NULL;
2567 	if ((data.netgroup = (char **)realloc(data.netgroup,
2568 		(netgcount + 1) * sizeof (char **))) == NULL) {
2569 		(void) fprintf(stderr, gettext("out of memory\n"));
2570 		exit(1);
2571 	}
2572 	data.netgroup[netgcount] = NULL;
2573 
2574 	if (rc == GENENT_OK) {
2575 		if (flags & F_VERBOSE)
2576 			(void) fprintf(stdout,
2577 			    gettext("Adding entry : %s\n"), data.name);
2578 
2579 		retval = (*cback)(&data, 0);
2580 
2581 		if (retval == LDAP_ALREADY_EXISTS) {
2582 			if (continue_onerror)
2583 				(void) fprintf(stderr, gettext(
2584 				"Entry: %s - already Exists, skipping it.\n"),
2585 				data.name);
2586 			else {
2587 				rc = GENENT_CBERR;
2588 				(void) fprintf(stderr,
2589 					gettext("Entry: %s - already Exists\n"),
2590 					data.name);
2591 			}
2592 		} else if (retval)
2593 			rc = GENENT_CBERR;
2594 	}
2595 
2596 	/* release memory allocated by strdup() */
2597 	for (i = 0; i < tripletcount; i++) {
2598 		free(data.triplet[i]);
2599 	}
2600 	for (i = 0; i < netgcount; i++) {
2601 		free(data.netgroup[i]);
2602 	}
2603 
2604 	free(data.name);
2605 	free(data.triplet);
2606 	free(data.netgroup);
2607 
2608 	return (rc);
2609 }
2610 
2611 static void
2612 dump_netgroup(ns_ldap_result_t *res)
2613 {
2614 	char	**value = NULL;
2615 	int	attr_count = 0;
2616 
2617 	value = __ns_ldap_getAttr(res->entry, "cn");
2618 	if ((value != NULL) && (value[0] != NULL))
2619 		(void) fprintf(stdout, "%s", value[0]);
2620 	else
2621 		return;
2622 	value = __ns_ldap_getAttr(res->entry, "nisNetgroupTriple");
2623 	if (value != NULL)
2624 		while (value[attr_count] != NULL) {
2625 			(void) fprintf(stdout, " %s", value[attr_count]);
2626 			attr_count++;
2627 		}
2628 	value = __ns_ldap_getAttr(res->entry, "memberNisNetgroup");
2629 	if (value != NULL)
2630 		while (value[attr_count] != NULL) {
2631 			(void) fprintf(stdout, " %s", value[attr_count]);
2632 			attr_count++;
2633 		}
2634 	(void) fprintf(stdout, "\n");
2635 
2636 }
2637 
2638 static int
2639 genent_automount(char *line, int (*cback)())
2640 {
2641 	char buf[BUFSIZ+1];
2642 	char *t, *s;
2643 	entry_col ecol[2];
2644 	struct _ns_automount data;
2645 	int retval = 1;
2646 	int rc = GENENT_OK;
2647 
2648 	/*
2649 	 * don't clobber our argument
2650 	 */
2651 	if (strlen(line) >= sizeof (buf)) {
2652 		(void) strcpy(parse_err_msg, "line too long");
2653 		return (GENENT_PARSEERR);
2654 		}
2655 
2656 	/* replace every tabspace with single space */
2657 	replace_tab2space(line);
2658 	(void) strcpy(buf, line);
2659 
2660 	/*
2661 	 * clear column data
2662 	 */
2663 	(void) memset((char *)ecol, 0, sizeof (ecol));
2664 
2665 	/*
2666 	 * key (col 0)
2667 	 */
2668 	t = buf;
2669 	while (t[0] == ' ')
2670 		t++;
2671 
2672 	if ((s = strchr(t, ' ')) == 0) {
2673 		return (GENENT_PARSEERR);
2674 	}
2675 	*s++ = 0;
2676 
2677 	ecol[0].ec_value.ec_value_val = t;
2678 	ecol[0].ec_value.ec_value_len = strlen(t)+1;
2679 	t = s;
2680 
2681 	while (t[0] == ' ')
2682 		t++;
2683 
2684 	/*
2685 	 * mapentry (col 1)
2686 	 */
2687 
2688 	ecol[1].ec_value.ec_value_val = t;
2689 	ecol[1].ec_value.ec_value_len = strlen(t)+1;
2690 
2691 	data.mapname = strdup(databasetype);
2692 	data.key = strdup(ecol[0].ec_value.ec_value_val);
2693 	data.value = strdup(ecol[1].ec_value.ec_value_val);
2694 
2695 	if (flags & F_VERBOSE)
2696 		(void) fprintf(stdout,
2697 		    gettext("Adding entry : %s\n"), data.key);
2698 
2699 	retval = (*cback)(&data, 0);
2700 
2701 	if (retval == LDAP_ALREADY_EXISTS) {
2702 		if (continue_onerror)
2703 			(void) fprintf(stderr,
2704 			gettext("Entry: %s - already Exists, skipping it.\n"),
2705 			data.key);
2706 		else {
2707 			rc = GENENT_CBERR;
2708 			(void) fprintf(stderr,
2709 				gettext("Entry: %s - already Exists\n"),
2710 				data.key);
2711 		}
2712 	} else if (retval)
2713 		rc = GENENT_CBERR;
2714 
2715 	free(data.mapname);
2716 	free(data.key);
2717 	free(data.value);
2718 	return (rc);
2719 }
2720 
2721 static void
2722 dump_automount(ns_ldap_result_t *res)
2723 {
2724 	char	**value = NULL;
2725 
2726 	if (res == NULL)
2727 		return;
2728 
2729 	value = __ns_ldap_getAttr(res->entry, "automountKey");
2730 	if (value != NULL) {
2731 		(void) fprintf(stdout, "%s", value[0]);
2732 		value = __ns_ldap_getAttr(res->entry, "automountInformation");
2733 		if (value != NULL)
2734 			(void) fprintf(stdout, "	%s\n", value[0]);
2735 		else
2736 			(void) fprintf(stdout, "\n");
2737 	}
2738 }
2739 
2740 
2741 /*
2742  * /etc/passwd
2743  *
2744  */
2745 
2746 static int
2747 genent_passwd(char *line, int (*cback)())
2748 {
2749 	char buf[BUFSIZ+1];
2750 	char *s, *t;
2751 	entry_col ecol[8];
2752 	int retval = 1;
2753 	char pname[BUFSIZ];
2754 
2755 	struct passwd	data;
2756 	int rc = GENENT_OK;
2757 
2758 
2759 	/*
2760 	 * don't clobber our argument
2761 	 */
2762 	if (strlen(line) >= sizeof (buf)) {
2763 		(void) strcpy(parse_err_msg, "line too long");
2764 		return (GENENT_PARSEERR);
2765 	}
2766 	(void) strcpy(buf, line);
2767 	t = buf;
2768 
2769 	/* ignore empty entries */
2770 	if (*t == '\0')
2771 		return (GENENT_OK);
2772 
2773 	/*
2774 	 * clear column data
2775 	 */
2776 	(void) memset((char *)ecol, 0, sizeof (ecol));
2777 
2778 	/*
2779 	 * name (col 0)
2780 	 */
2781 	if ((s = strchr(t, ':')) == 0) {
2782 		(void) strcpy(parse_err_msg, "no password");
2783 		return (GENENT_PARSEERR);
2784 	}
2785 	*s++ = 0;
2786 	ecol[0].ec_value.ec_value_val = t;
2787 	ecol[0].ec_value.ec_value_len = strlen(t)+1;
2788 	t = s;
2789 
2790 	/*
2791 	 * passwd (col 1)
2792 	 */
2793 	if ((s = strchr(t, ':')) == 0) {
2794 		(void) strcpy(parse_err_msg, "no uid");
2795 		return (GENENT_PARSEERR);
2796 	}
2797 	*s++ = 0;
2798 
2799 	ecol[1].ec_value.ec_value_val = t;
2800 	ecol[1].ec_value.ec_value_len = strlen(t)+1;
2801 
2802 	t = s;
2803 
2804 	/*
2805 	 * uid (col 2)
2806 	 */
2807 	if ((s = strchr(t, ':')) == 0 || s == t) {
2808 		(void) strcpy(parse_err_msg, "no gid");
2809 		return (GENENT_PARSEERR);
2810 	}
2811 	*s++ = 0;
2812 	ecol[2].ec_value.ec_value_val = t;
2813 	ecol[2].ec_value.ec_value_len = strlen(t)+1;
2814 	t = s;
2815 
2816 	/*
2817 	 * gid (col 3)
2818 	 */
2819 	if ((s = strchr(t, ':')) == 0 || s == t) {
2820 		(void) strcpy(parse_err_msg, "no gcos");
2821 		return (GENENT_PARSEERR);
2822 	}
2823 	*s++ = 0;
2824 	ecol[3].ec_value.ec_value_val = t;
2825 	ecol[3].ec_value.ec_value_len = strlen(t)+1;
2826 	t = s;
2827 
2828 	/*
2829 	 * gcos (col 4)
2830 	 */
2831 	if ((s = strchr(t, ':')) == 0) {
2832 		(void) strcpy(parse_err_msg, "no home");
2833 		return (GENENT_PARSEERR);
2834 	}
2835 	*s++ = 0;
2836 	ecol[4].ec_value.ec_value_val = t;
2837 	ecol[4].ec_value.ec_value_len = strlen(t)+1;
2838 	t = s;
2839 
2840 	/*
2841 	 * home (col 5)
2842 	 */
2843 	if ((s = strchr(t, ':')) == 0) {
2844 		(void) strcpy(parse_err_msg, "no shell");
2845 		return (GENENT_PARSEERR);
2846 	}
2847 	*s++ = 0;
2848 	ecol[5].ec_value.ec_value_val = t;
2849 	ecol[5].ec_value.ec_value_len = strlen(t)+1;
2850 	t = s;
2851 
2852 	/*
2853 	 * shell (col 6)
2854 	 */
2855 	ecol[6].ec_value.ec_value_val = t;
2856 	ecol[6].ec_value.ec_value_len = strlen(t)+1;
2857 
2858 	/*
2859 	 * build entry
2860 	 */
2861 	data.pw_name = strdup(ecol[0].ec_value.ec_value_val);
2862 
2863 	if (flags & F_PASSWD) {
2864 		/* Add {crypt} before passwd entry */
2865 		(void) snprintf(pname, sizeof (pname), "{crypt}%s",
2866 		    ecol[1].ec_value.ec_value_val);
2867 		data.pw_passwd = strdup(pname);
2868 	}
2869 	else
2870 		data.pw_passwd = NULL;
2871 
2872 	if (ecol[2].ec_value.ec_value_val != NULL &&
2873 	    ecol[2].ec_value.ec_value_val[0] != '\0') {
2874 		data.pw_uid = ascii_to_int(ecol[2].ec_value.ec_value_val);
2875 		if (data.pw_uid == -1) {
2876 			(void) snprintf(parse_err_msg, sizeof (parse_err_msg),
2877 			    "invalid uid : %s", ecol[2].ec_value.ec_value_val);
2878 		return (GENENT_PARSEERR);
2879 		}
2880 	} else
2881 		data.pw_uid = -1;
2882 
2883 	if (ecol[3].ec_value.ec_value_val != NULL &&
2884 		ecol[3].ec_value.ec_value_val[0] != '\0') {
2885 
2886 		data.pw_gid = ascii_to_int(ecol[3].ec_value.ec_value_val);
2887 		if (data.pw_gid == -1) {
2888 			(void) snprintf(parse_err_msg, sizeof (parse_err_msg),
2889 			    "invalid gid : %s", ecol[3].ec_value.ec_value_val);
2890 		return (GENENT_PARSEERR);
2891 		}
2892 	} else
2893 		data.pw_gid = -1;
2894 
2895 	data.pw_age = NULL;
2896 	data.pw_comment = NULL;
2897 	data.pw_gecos = strdup(ecol[4].ec_value.ec_value_val);
2898 	data.pw_dir = strdup(ecol[5].ec_value.ec_value_val);
2899 	data.pw_shell = strdup(ecol[6].ec_value.ec_value_val);
2900 
2901 	if (flags & F_VERBOSE)
2902 		(void) fprintf(stdout,
2903 		    gettext("Adding entry : %s\n"), data.pw_name);
2904 
2905 	retval = (*cback)(&data, 0);
2906 
2907 	if (retval == LDAP_ALREADY_EXISTS) {
2908 		if (continue_onerror)
2909 			(void) fprintf(stderr,
2910 			gettext("Entry: %s - already Exists, skipping it.\n"),
2911 			data.pw_name);
2912 		else {
2913 			rc = GENENT_CBERR;
2914 			(void) fprintf(stderr,
2915 				gettext("Entry: %s - already Exists\n"),
2916 				data.pw_name);
2917 		}
2918 	} else if (retval)
2919 		rc = GENENT_CBERR;
2920 
2921 	free(data.pw_name);
2922 	free(data.pw_gecos);
2923 	free(data.pw_dir);
2924 	free(data.pw_shell);
2925 	return (rc);
2926 }
2927 
2928 
2929 static void
2930 dump_passwd(ns_ldap_result_t *res)
2931 {
2932 	char    **value = NULL;
2933 	char	pnam[256];
2934 
2935 	value = __ns_ldap_getAttr(res->entry, "uid");
2936 	if (value == NULL)
2937 		return;
2938 	else
2939 		(void) fprintf(stdout, "%s:", value[0]);
2940 	value = __ns_ldap_getAttr(res->entry, "userPassword");
2941 	if (value == NULL)
2942 		(void) fprintf(stdout, "*:");
2943 	else {
2944 		(void) strcpy(pnam, value[0]);
2945 		if (strncasecmp(value[0], "{crypt}", 7) == 0)
2946 		(void) fprintf(stdout, "%s:", (pnam+7));
2947 		else
2948 			(void) fprintf(stdout, "*:");
2949 	}
2950 	value = __ns_ldap_getAttr(res->entry, "uidNumber");
2951 	if (value && value[0])
2952 		(void) fprintf(stdout, "%s:", value[0]);
2953 	value = __ns_ldap_getAttr(res->entry, "gidNumber");
2954 	if (value && value[0])
2955 		(void) fprintf(stdout, "%s:", value[0]);
2956 	value = __ns_ldap_getAttr(res->entry, "gecos");
2957 	if (value == NULL)
2958 		(void) fprintf(stdout, ":");
2959 	else
2960 		(void) fprintf(stdout, "%s:", value[0]);
2961 	value = __ns_ldap_getAttr(res->entry, "homeDirectory");
2962 	if (value == NULL)
2963 		(void) fprintf(stdout, ":");
2964 	else
2965 		(void) fprintf(stdout, "%s:", value[0]);
2966 	value = __ns_ldap_getAttr(res->entry, "loginShell");
2967 	if (value == NULL)
2968 		(void) fprintf(stdout, "\n");
2969 	else
2970 		(void) fprintf(stdout, "%s\n", value[0]);
2971 
2972 }
2973 
2974 /*
2975  * /etc/shadow
2976  */
2977 
2978 static int
2979 genent_shadow(char *line, int (*cback)())
2980 {
2981 	char buf[BUFSIZ+1];
2982 	char *s, *t;
2983 	entry_col ecol[9];
2984 	char pname[BUFSIZ];
2985 
2986 	struct spwd	data;
2987 	int spflag;
2988 
2989 
2990 	/*
2991 	 * don't clobber our argument
2992 	 */
2993 	if (strlen(line) >= sizeof (buf)) {
2994 		(void) strcpy(parse_err_msg, "line too long");
2995 		return (GENENT_PARSEERR);
2996 	}
2997 	(void) strcpy(buf, line);
2998 	t = buf;
2999 
3000 	/* ignore empty entries */
3001 	if (*t == '\0')
3002 		return (GENENT_OK);
3003 
3004 	/*
3005 	 * clear column data
3006 	 */
3007 	(void) memset((char *)ecol, 0, sizeof (ecol));
3008 
3009 	/*
3010 	 * name (col 0)
3011 	 */
3012 	if ((s = strchr(t, ':')) == 0) {
3013 		(void) strcpy(parse_err_msg, "no uid");
3014 		return (GENENT_PARSEERR);
3015 	}
3016 	*s++ = 0;
3017 	ecol[0].ec_value.ec_value_val = t;
3018 	ecol[0].ec_value.ec_value_len = strlen(t)+1;
3019 	t = s;
3020 
3021 	/*
3022 	 * passwd (col 1)
3023 	 */
3024 	if ((s = strchr(t, ':')) == 0) {
3025 		(void) strcpy(parse_err_msg, "Improper format");
3026 		return (GENENT_PARSEERR);
3027 	}
3028 	*s++ = 0;
3029 
3030 		ecol[1].ec_value.ec_value_val = t;
3031 		ecol[1].ec_value.ec_value_len = strlen(t)+1;
3032 
3033 	t = s;
3034 
3035 	/*
3036 	 * shadow last change (col 2)
3037 	 */
3038 	if ((s = strchr(t, ':')) == 0) {
3039 		(void) strcpy(parse_err_msg, "Improper format");
3040 		return (GENENT_PARSEERR);
3041 	}
3042 	*s++ = 0;
3043 	ecol[2].ec_value.ec_value_val = t;
3044 	ecol[2].ec_value.ec_value_len = strlen(t)+1;
3045 	t = s;
3046 
3047 	/*
3048 	 * shadow min (col 3)
3049 	 */
3050 	if ((s = strchr(t, ':')) == 0) {
3051 		(void) strcpy(parse_err_msg, "Improper format");
3052 		return (GENENT_PARSEERR);
3053 	}
3054 	*s++ = 0;
3055 	ecol[3].ec_value.ec_value_val = t;
3056 	ecol[3].ec_value.ec_value_len = strlen(t)+1;
3057 	t = s;
3058 
3059 	/*
3060 	 * shadow max (col 4)
3061 	 */
3062 	if ((s = strchr(t, ':')) == 0) {
3063 		(void) strcpy(parse_err_msg, "Improper format");
3064 		return (GENENT_PARSEERR);
3065 	}
3066 	*s++ = 0;
3067 	ecol[4].ec_value.ec_value_val = t;
3068 	ecol[4].ec_value.ec_value_len = strlen(t)+1;
3069 	t = s;
3070 
3071 	/*
3072 	 * shadow warn (col 5)
3073 	 */
3074 	if ((s = strchr(t, ':')) == 0) {
3075 		(void) strcpy(parse_err_msg, "Improper format");
3076 		return (GENENT_PARSEERR);
3077 	}
3078 	*s++ = 0;
3079 	ecol[5].ec_value.ec_value_val = t;
3080 	ecol[5].ec_value.ec_value_len = strlen(t)+1;
3081 	t = s;
3082 
3083 	/*
3084 	 * shadow inactive (col 6)
3085 	 */
3086 	if ((s = strchr(t, ':')) != 0) {
3087 	*s++ = 0;
3088 	ecol[6].ec_value.ec_value_val = t;
3089 	ecol[6].ec_value.ec_value_len = strlen(t)+1;
3090 	t = s;
3091 	}
3092 
3093 	/*
3094 	 * shadow expire  (col 7)
3095 	 */
3096 	if ((s = strchr(t, ':')) != 0) {
3097 	*s++ = 0;
3098 	ecol[7].ec_value.ec_value_val = t;
3099 	ecol[7].ec_value.ec_value_len = strlen(t)+1;
3100 	t = s;
3101 
3102 	/*
3103 	 * flag (col 8)
3104 	 */
3105 	ecol[8].ec_value.ec_value_val = t;
3106 	ecol[8].ec_value.ec_value_len = strlen(t)+1;
3107 	}
3108 
3109 	/*
3110 	 * build entry
3111 	 */
3112 
3113 	data.sp_namp = strdup(ecol[0].ec_value.ec_value_val);
3114 
3115 	if (ecol[1].ec_value.ec_value_val != NULL &&
3116 		ecol[1].ec_value.ec_value_val[0] != '\0') {
3117 		/* Add {crypt} before passwd entry */
3118 		(void) snprintf(pname, sizeof (pname), "{crypt}%s",
3119 		    ecol[1].ec_value.ec_value_val);
3120 		data.sp_pwdp = strdup(pname);
3121 	} else
3122 		data.sp_pwdp = NULL;
3123 
3124 	if (ecol[2].ec_value.ec_value_val != NULL &&
3125 		ecol[2].ec_value.ec_value_val[0] != '\0') {
3126 
3127 		data.sp_lstchg = ascii_to_int(ecol[2].ec_value.ec_value_val);
3128 		if (data.sp_lstchg < -1) {
3129 			(void) snprintf(parse_err_msg, sizeof (parse_err_msg),
3130 			    "invalid last changed date: %s",
3131 			    ecol[2].ec_value.ec_value_val);
3132 		return (GENENT_PARSEERR);
3133 		}
3134 	} else
3135 		data.sp_lstchg = -1;
3136 
3137 	if (ecol[3].ec_value.ec_value_val != NULL &&
3138 		ecol[3].ec_value.ec_value_val[0] != '\0') {
3139 
3140 		data.sp_min = ascii_to_int(ecol[3].ec_value.ec_value_val);
3141 		if (data.sp_min < -1) {
3142 			(void) snprintf(parse_err_msg, sizeof (parse_err_msg),
3143 			    "invalid sp_min : %s",
3144 			    ecol[3].ec_value.ec_value_val);
3145 		return (GENENT_PARSEERR);
3146 		}
3147 	} else
3148 		data.sp_min = -1;
3149 
3150 	if (ecol[4].ec_value.ec_value_val != NULL &&
3151 		ecol[4].ec_value.ec_value_val[0] != '\0') {
3152 
3153 		data.sp_max = ascii_to_int(ecol[4].ec_value.ec_value_val);
3154 		if (data.sp_max < -1) {
3155 			(void) snprintf(parse_err_msg, sizeof (parse_err_msg),
3156 			    "invalid sp_max : %s",
3157 			    ecol[4].ec_value.ec_value_val);
3158 		return (GENENT_PARSEERR);
3159 		}
3160 	} else
3161 		data.sp_max = -1;
3162 
3163 	if (ecol[5].ec_value.ec_value_val != NULL &&
3164 		ecol[5].ec_value.ec_value_val[0] != '\0') {
3165 
3166 		data.sp_warn = ascii_to_int(ecol[5].ec_value.ec_value_val);
3167 		if (data.sp_warn < -1) {
3168 			(void) snprintf(parse_err_msg, sizeof (parse_err_msg),
3169 			    "invalid sp_warn : %s",
3170 			    ecol[5].ec_value.ec_value_val);
3171 		return (GENENT_PARSEERR);
3172 		}
3173 	} else
3174 		data.sp_warn = -1;
3175 
3176 	if (ecol[6].ec_value.ec_value_val != NULL &&
3177 		ecol[6].ec_value.ec_value_val[0] != '\0') {
3178 
3179 		data.sp_inact = ascii_to_int(ecol[6].ec_value.ec_value_val);
3180 		if (data.sp_inact < -1) {
3181 			(void) snprintf(parse_err_msg, sizeof (parse_err_msg),
3182 			    "invalid sp_inact : %s",
3183 			    ecol[6].ec_value.ec_value_val);
3184 		return (GENENT_PARSEERR);
3185 		}
3186 	} else
3187 		data.sp_inact = -1;
3188 
3189 	if (ecol[7].ec_value.ec_value_val != NULL &&
3190 		ecol[7].ec_value.ec_value_val[0] != '\0') {
3191 
3192 		data.sp_expire = ascii_to_int(ecol[7].ec_value.ec_value_val);
3193 		if (data.sp_expire < -1) {
3194 			(void) snprintf(parse_err_msg, sizeof (parse_err_msg),
3195 			    "invalid login expiry date : %s",
3196 			    ecol[7].ec_value.ec_value_val);
3197 		return (GENENT_PARSEERR);
3198 		}
3199 	} else
3200 		data.sp_expire = -1;
3201 
3202 	if (ecol[8].ec_value.ec_value_val != NULL &&
3203 		ecol[8].ec_value.ec_value_val[0] != '\0') {
3204 
3205 		/*
3206 		 * data.sp_flag is an unsigned int,
3207 		 * assign -1 to it, make no sense.
3208 		 * Use spflag here to avoid lint warning.
3209 		 */
3210 		spflag = ascii_to_int(ecol[8].ec_value.ec_value_val);
3211 		if (spflag < 0) {
3212 			(void) snprintf(parse_err_msg, sizeof (parse_err_msg),
3213 			    "invalid flag value: %s",
3214 			    ecol[8].ec_value.ec_value_val);
3215 		return (GENENT_PARSEERR);
3216 		} else
3217 			data.sp_flag = spflag;
3218 	} else
3219 		data.sp_flag = 0;
3220 
3221 	if (flags & F_VERBOSE)
3222 		(void) fprintf(stdout,
3223 		    gettext("Adding entry : %s\n"), data.sp_namp);
3224 
3225 	if ((*cback)(&data, 1) && (continue_onerror == 0))
3226 		return (GENENT_CBERR);
3227 
3228 	free(data.sp_namp);
3229 	free(data.sp_pwdp);
3230 	return (GENENT_OK);
3231 }
3232 
3233 static void
3234 dump_shadow(ns_ldap_result_t *res)
3235 {
3236 	char    **value = NULL;
3237 	char   pnam[256];
3238 
3239 	value = __ns_ldap_getAttr(res->entry, "uid");
3240 	if (value == NULL)
3241 		return;
3242 	else
3243 		(void) fprintf(stdout, "%s:", value[0]);
3244 	value = __ns_ldap_getAttr(res->entry, "userPassword");
3245 	if (value == NULL)
3246 		(void) fprintf(stdout, "*:");
3247 	else {
3248 		(void) strcpy(pnam, value[0]);
3249 		if (strncasecmp(value[0], "{crypt}", 7) == 0)
3250 		(void) fprintf(stdout, "%s:", (pnam+7));
3251 		else
3252 			(void) fprintf(stdout, "*:");
3253 	}
3254 	value = __ns_ldap_getAttr(res->entry, "shadowLastChange");
3255 	if (value == NULL)
3256 		(void) fprintf(stdout, ":");
3257 	else
3258 		(void) fprintf(stdout, "%s:", value[0]);
3259 	value = __ns_ldap_getAttr(res->entry, "shadowMin");
3260 	if (value == NULL)
3261 		(void) fprintf(stdout, ":");
3262 	else
3263 		(void) fprintf(stdout, "%s:", value[0]);
3264 	value = __ns_ldap_getAttr(res->entry, "shadowMax");
3265 	if (value == NULL)
3266 		(void) fprintf(stdout, ":");
3267 	else
3268 		(void) fprintf(stdout, "%s:", value[0]);
3269 
3270 	/* ignore shadowWarning, shadowInactive, shadowExpire, shadowFlag */
3271 	(void) fprintf(stdout, ":::\n");
3272 
3273 }
3274 
3275 
3276 static int
3277 genent_bootparams(char *line, int (*cback)())
3278 {
3279 	char buf[BUFSIZ+1];
3280 	char *t;
3281 	entry_col ecol[2];
3282 	int ctr = 0, retval = 1;
3283 
3284 	struct _ns_bootp data;
3285 	char *parameter;
3286 	int rc = GENENT_OK;
3287 
3288 	/*
3289 	 * don't clobber our argument
3290 	 */
3291 	if (strlen(line) >= sizeof (buf)) {
3292 		(void) strcpy(parse_err_msg, "line too long");
3293 		return (GENENT_PARSEERR);
3294 	}
3295 	(void) strcpy(buf, line);
3296 
3297 	/*
3298 	 * clear column data
3299 	 */
3300 	(void) memset((char *)ecol, 0, sizeof (ecol));
3301 
3302 
3303 	/*
3304 	 * cname (col 0)
3305 	 */
3306 	if ((t = strtok(buf, " \t")) == 0) {
3307 		(void) strcpy(parse_err_msg, "no cname");
3308 		return (GENENT_PARSEERR);
3309 	}
3310 	ecol[0].ec_value.ec_value_val = t;
3311 	ecol[0].ec_value.ec_value_len = strlen(t)+1;
3312 
3313 
3314 
3315 	/* build entry */
3316 	data.name = strdup(ecol[0].ec_value.ec_value_val);
3317 
3318 	/*
3319 	 * name (col 1)
3320 	 */
3321 
3322 	data.param = NULL;
3323 
3324 	do {
3325 
3326 		/*
3327 		 * don't clobber comment in canonical entry
3328 		 */
3329 
3330 
3331 		ecol[1].ec_value.ec_value_val = t;
3332 		ecol[1].ec_value.ec_value_len = strlen(t)+1;
3333 
3334 		ctr++;
3335 		parameter = strdup(ecol[1].ec_value.ec_value_val);
3336 		if ((data.param = (char **)realloc(data.param,
3337 			(ctr + 1) * sizeof (char **))) == NULL) {
3338 			(void) fprintf(stderr, gettext("out of memory\n"));
3339 			exit(1);
3340 		}
3341 		data.param[ctr-1] = parameter;
3342 
3343 	} while (t = strtok(NULL, " \t"));
3344 
3345 
3346 	/* End the list of all the aliases by NULL */
3347 	if ((data.param = (char **)realloc(data.param,
3348 		(ctr + 1) * sizeof (char **))) == NULL) {
3349 		(void) fprintf(stderr, gettext("out of memory\n"));
3350 		exit(1);
3351 	}
3352 	data.param[ctr] = NULL;
3353 
3354 	if (flags & F_VERBOSE)
3355 		(void) fprintf(stdout,
3356 		    gettext("Adding entry : %s\n"), data.name);
3357 
3358 	retval = (*cback)(&data, 0);
3359 
3360 	if (retval == LDAP_ALREADY_EXISTS) {
3361 		if (continue_onerror)
3362 			(void) fprintf(stderr,
3363 			gettext("Entry: %s - already Exists, skipping it.\n"),
3364 			data.name);
3365 		else {
3366 			rc = GENENT_CBERR;
3367 			(void) fprintf(stderr,
3368 				gettext("Entry: %s - already Exists\n"),
3369 				data.name);
3370 		}
3371 	} else if (retval)
3372 		rc = GENENT_CBERR;
3373 
3374 	free(data.name);
3375 	free(data.param);
3376 
3377 	return (rc);
3378 
3379 }
3380 
3381 
3382 static void
3383 dump_bootparams(ns_ldap_result_t *res)
3384 {
3385 	char	**value = NULL;
3386 	int		attr_count = 0;
3387 
3388 	value = __ns_ldap_getAttr(res->entry, "cn");
3389 	if (value[0] != NULL)
3390 		(void) fprintf(stdout, "%s", value[0]);
3391 	value = __ns_ldap_getAttr(res->entry, "bootParameter");
3392 	if (value != NULL)
3393 		while (value[attr_count] != NULL) {
3394 		(void) fprintf(stdout, "\t%s", value[attr_count]);
3395 			attr_count++;
3396 		}
3397 	(void) fprintf(stdout, "\n");
3398 
3399 
3400 }
3401 
3402 static char *
3403 fget_line_at(struct line_buf *line, int n, FILE *fp)
3404 {
3405 	int c;
3406 
3407 	line->len = n;
3408 
3409 	for (;;) {
3410 		c = fgetc(fp);
3411 		if (c == -1)
3412 			break;
3413 		if (line->len >= line->alloc)
3414 			line_buf_expand(line);
3415 		line->str[line->len++] = c;
3416 
3417 		if (c == '\n')
3418 			break;
3419 	}
3420 
3421 	/* Null Terminate */
3422 	if (line->len >= line->alloc)
3423 		line_buf_expand(line);
3424 	line->str[line->len++] = 0;
3425 
3426 	/* if no characters are read, return NULL to indicate EOF */
3427 	if (line->str[0] == '\0')
3428 		return (0);
3429 
3430 	return (line->str);
3431 }
3432 
3433 /*
3434  * return a line from the file, discarding comments and blank lines
3435  */
3436 static int
3437 filedbmline_comment(struct line_buf *line, FILE *etcf, int *lineno,
3438     struct file_loc *loc)
3439 {
3440 	int i, len = 0;
3441 
3442 	loc->offset = ftell(etcf);
3443 	for (;;) {
3444 		if (fget_line_at(line, len, etcf) == 0)
3445 			return (0);
3446 
3447 		if (lineno)
3448 			(*lineno)++;
3449 
3450 		len = strlen(line->str);
3451 		if (len >= 2 &&
3452 		    line->str[0] != '#' &&
3453 		    line->str[len-2] == '\\' && line->str[len-1] == '\n') {
3454 			line->str[len-2] = 0;
3455 			len -= 2;
3456 			continue;    /* append next line at end */
3457 		}
3458 
3459 		if (line->str[len-1] == '\n') {
3460 			line->str[len-1] = 0;
3461 			len -= 1;
3462 		}
3463 
3464 		/*
3465 		 * Skip lines where '#' is the first non-blank character.
3466 		 */
3467 		for (i = 0; i < len; i++) {
3468 			if (line->str[i] == '#') {
3469 				line->str[i] = '\0';
3470 				len = i;
3471 				break;
3472 			}
3473 			if (line->str[i] != ' ' && line->str[i] != '\t')
3474 				break;
3475 		}
3476 
3477 		/*
3478 		 * A line with one or more white space characters followed
3479 		 * by a comment will now be blank. The special case of a
3480 		 * line with '#' in the first byte will have len == 0.
3481 		 */
3482 		if (len > 0 && !blankline(line->str))
3483 			break;
3484 
3485 		len = 0;
3486 		loc->offset = ftell(etcf);
3487 	}
3488 
3489 	loc->size = len;
3490 	return (1);
3491 }
3492 
3493 /*
3494  * return a line from the file, discarding comments, blanks, and '+' lines
3495  */
3496 static int
3497 filedbmline_plus(struct line_buf *line, FILE *etcf, int *lineno,
3498     struct file_loc *loc)
3499 {
3500 	int len = 0;
3501 
3502 	loc->offset = ftell(etcf);
3503 	for (;;) {
3504 		if (fget_line_at(line, len, etcf) == 0)
3505 			return (0);
3506 
3507 		if (lineno)
3508 			(*lineno)++;
3509 
3510 		len = strlen(line->str);
3511 		if (line->str[len-1] == '\n') {
3512 			line->str[len-1] = 0;
3513 			len -= 1;
3514 		}
3515 
3516 		if (!blankline(line->str) &&
3517 		line->str[0] != '+' && line->str[0] != '-' &&
3518 		line->str[0] != '#')
3519 			break;
3520 
3521 		len = 0;
3522 		loc->offset = ftell(etcf);
3523 	}
3524 
3525 	loc->size = len;
3526 	return (1);
3527 }
3528 
3529 
3530 /* Populating the ttypelist structure */
3531 
3532 static struct ttypelist_t ttypelist[] = {
3533 	{ NS_LDAP_TYPE_HOSTS, genent_hosts, dump_hosts,
3534 		filedbmline_comment, "iphost" },
3535 	{ NS_LDAP_TYPE_IPNODES, genent_hosts, dump_hosts,
3536 		filedbmline_comment, "iphost" },
3537 	{ NS_LDAP_TYPE_RPC, genent_rpc, dump_rpc,
3538 		filedbmline_comment, "oncrpc" },
3539 	{ NS_LDAP_TYPE_PROTOCOLS, genent_protocols, dump_protocols,
3540 		filedbmline_comment, "ipprotocol" },
3541 	{ NS_LDAP_TYPE_NETWORKS, genent_networks, dump_networks,
3542 		filedbmline_comment, "ipnetwork"  },
3543 	{ NS_LDAP_TYPE_SERVICES, genent_services, dump_services,
3544 		filedbmline_comment, "ipservice" },
3545 	{ NS_LDAP_TYPE_GROUP, genent_group, dump_group,
3546 		filedbmline_plus, "posixgroup" },
3547 	{ NS_LDAP_TYPE_NETMASKS, genent_netmasks, dump_netmasks,
3548 		filedbmline_comment, "ipnetwork" },
3549 	{ NS_LDAP_TYPE_ETHERS, genent_ethers, dump_ethers,
3550 		filedbmline_comment, "ieee802Device" },
3551 	{ NS_LDAP_TYPE_NETGROUP, genent_netgroup, dump_netgroup,
3552 		filedbmline_comment, "nisnetgroup" },
3553 	{ NS_LDAP_TYPE_BOOTPARAMS, genent_bootparams, dump_bootparams,
3554 		filedbmline_comment, "bootableDevice" },
3555 	{ NS_LDAP_TYPE_PUBLICKEY, genent_publickey, NULL /* dump_publickey */,
3556 		filedbmline_comment, "niskeyobject" },
3557 	{ NS_LDAP_TYPE_PASSWD, genent_passwd, dump_passwd,
3558 		filedbmline_plus, "posixaccount" },
3559 	{ NS_LDAP_TYPE_SHADOW, genent_shadow, dump_shadow,
3560 		filedbmline_plus, "shadowaccount" },
3561 	{ NS_LDAP_TYPE_ALIASES, genent_aliases, dump_aliases,
3562 		filedbmline_plus, "mailGroup" },
3563 	{ NS_LDAP_TYPE_AUTOMOUNT, genent_automount, dump_automount,
3564 		filedbmline_comment, "automount" },
3565 	{ NS_LDAP_TYPE_USERATTR, genent_user_attr, dump_user_attr,
3566 		filedbmline_comment, "SolarisUserAttr" },
3567 	{ NS_LDAP_TYPE_PROFILE, genent_prof_attr, dump_prof_attr,
3568 		filedbmline_comment, "SolarisProfAttr" },
3569 	{ NS_LDAP_TYPE_EXECATTR, genent_exec_attr, dump_exec_attr,
3570 		filedbmline_comment, "SolarisExecAttr" },
3571 	{ NS_LDAP_TYPE_AUTHATTR, genent_auth_attr, dump_auth_attr,
3572 		filedbmline_comment, "SolarisAuthAttr" },
3573 	{ NS_LDAP_TYPE_AUUSER, genent_audit_user, dump_audit_user,
3574 		filedbmline_comment, "SolarisAuditUser" },
3575 	{ 0, 0, 0, 0, 0 }
3576 };
3577 
3578 
3579 
3580 
3581 static int lineno = 0;
3582 
3583 static	void
3584 addfile()
3585 {
3586 	struct line_buf line;
3587 	struct file_loc loc;
3588 
3589 	/* Initializing the Line Buffer */
3590 	line_buf_init(&line);
3591 
3592 	/* Loop through all the lines in the file */
3593 	while (tt->filedbmline(&line, etcf, &lineno, &loc)) {
3594 		switch ((*(tt->genent))(line.str, addentry)) {
3595 		case GENENT_OK:
3596 			break;
3597 		case GENENT_PARSEERR:
3598 			(void) fprintf(stderr,
3599 			    gettext("parse error: %s (line %d)\n"),
3600 			    parse_err_msg, lineno);
3601 			exit_val = 1;
3602 			break;
3603 		case GENENT_CBERR:
3604 			(void) fprintf(stderr,
3605 			    gettext("Error while adding line: %s\n"),
3606 			    line.str);
3607 			exit_val = 2;
3608 			free(line.str);
3609 			return;
3610 			break;
3611 		case GENENT_ERR:
3612 			(void) fprintf(stderr,
3613 			    gettext("Internal Error while adding line: %s\n"),
3614 			    line.str);
3615 			exit_val = 3;
3616 			free(line.str);
3617 			return;
3618 			break;
3619 		}
3620 	}
3621 	free(line.str);
3622 }
3623 
3624 static void
3625 dumptable(char *service)
3626 {
3627 
3628 	ns_ldap_result_t *eres = NULL;
3629 	ns_ldap_error_t *err = NULL;
3630 	int	rc = 0, success = 0;
3631 	char	filter[BUFSIZ];
3632 	int	done = 0;
3633 	void	*cookie = NULL;
3634 
3635 	/* set the appropriate filter */
3636 	if (strcmp(tt->ttype, NS_LDAP_TYPE_PROFILE) == 0) {
3637 		/*
3638 		 * prof_attr entries are SolarisProfAttr
3639 		 * without AUXILIARY SolarisExecAttr
3640 		 */
3641 		(void) snprintf(filter, sizeof (filter),
3642 		    "(&(objectclass=%s)(!(objectclass=SolarisExecAttr)))",
3643 		    tt->objclass);
3644 	} else
3645 		(void) snprintf(filter, sizeof (filter),
3646 		    "(objectclass=%s)", tt->objclass);
3647 
3648 	if (flags & F_VERBOSE)
3649 		(void) fprintf(stdout, gettext("FILTER = %s\n"), filter);
3650 
3651 	/* Pass cred only if supplied. Cred is not always needed for dump */
3652 	if (authority.cred.unix_cred.userID == NULL ||
3653 	    authority.cred.unix_cred.passwd == NULL)
3654 		rc = __ns_ldap_firstEntry(service, filter, NULL, NULL,
3655 		    NULL, NS_LDAP_HARD, &cookie, &eres, &err, NULL);
3656 	else
3657 		rc = __ns_ldap_firstEntry(service, filter, NULL, NULL,
3658 		    &authority, NS_LDAP_HARD, &cookie, &eres, &err, NULL);
3659 
3660 	switch (rc) {
3661 	case NS_LDAP_SUCCESS:
3662 		nent_add++;
3663 		success = 1;
3664 		if (eres != NULL) {
3665 			if (strcmp(databasetype, "publickey") == 0)
3666 				dump_publickey(eres, service);
3667 			else
3668 				(*(tt->dump))(eres);
3669 		}
3670 		else
3671 			(void) fprintf(stderr, gettext("No entries found.\n"));
3672 		break;
3673 
3674 	case NS_LDAP_OP_FAILED:
3675 		exit_val = 2;
3676 		(void) fprintf(stderr, gettext("operation failed.\n"));
3677 		break;
3678 
3679 	case NS_LDAP_INVALID_PARAM:
3680 		exit_val = 2;
3681 		(void) fprintf(stderr,
3682 		    gettext("invalid parameter(s) passed.\n"));
3683 		break;
3684 
3685 	case NS_LDAP_NOTFOUND:
3686 		exit_val = 2;
3687 		(void) fprintf(stderr, gettext("entry not found.\n"));
3688 		break;
3689 
3690 	case NS_LDAP_MEMORY:
3691 		exit_val = 2;
3692 		(void) fprintf(stderr,
3693 			gettext("internal memory allocation error.\n"));
3694 		break;
3695 
3696 	case NS_LDAP_CONFIG:
3697 		exit_val = 2;
3698 		(void) fprintf(stderr,
3699 			gettext("LDAP Configuration problem.\n"));
3700 		perr(err);
3701 		break;
3702 
3703 	case NS_LDAP_PARTIAL:
3704 		exit_val = 2;
3705 		(void) fprintf(stderr,
3706 			gettext("partial result returned\n"));
3707 		perr(err);
3708 		break;
3709 
3710 	case NS_LDAP_INTERNAL:
3711 		exit_val = 2;
3712 		(void) fprintf(stderr,
3713 			gettext("internal LDAP error occured.\n"));
3714 		perr(err);
3715 		break;
3716 	}
3717 
3718 	if (eres != NULL) {
3719 		(void) __ns_ldap_freeResult(&eres);
3720 		eres = NULL;
3721 	}
3722 
3723 	if (success) {
3724 		while (!done) {
3725 			rc = __ns_ldap_nextEntry(cookie, &eres, &err);
3726 			if (rc != NS_LDAP_SUCCESS || eres  == NULL) {
3727 				done = 1;
3728 				continue;
3729 			}
3730 
3731 			/* Print the result */
3732 			if (eres != NULL) {
3733 				if (strcmp(databasetype, "publickey") == 0)
3734 					dump_publickey(eres, service);
3735 				else
3736 					(*(tt->dump))(eres);
3737 				(void) __ns_ldap_freeResult(&eres);
3738 				eres = NULL;
3739 			}
3740 		}
3741 	}
3742 }
3743 
3744 int
3745 main(int argc, char **argv)
3746 {
3747 	char	*password;
3748 	int	c;
3749 	int	rc;
3750 	int	ldaprc;
3751 	int		authstried = 0;
3752 	int		supportedauth = 0;
3753 	int		op = OP_ADD;
3754 	char	*ttype, *authmech = 0, *etcfile = 0;
3755 	char	ps[LDAP_MAXNAMELEN]; /* Temporary password variable */
3756 	char	filter[BUFSIZ];
3757 	void	**paramVal = NULL;
3758 	ns_auth_t	**app;
3759 	ns_auth_t	**authpp = NULL;
3760 	ns_auth_t	*authp = NULL;
3761 	ns_ldap_error_t	*errorp = NULL;
3762 	ns_ldap_result_t *resultp;
3763 	ns_ldap_entry_t *e;
3764 	int	flag = 0;
3765 	int	version1 = 0;
3766 
3767 	(void) setlocale(LC_ALL, "");
3768 	(void) textdomain(TEXT_DOMAIN);
3769 
3770 	openlog("ldapaddent", LOG_PID, LOG_USER);
3771 
3772 	inputbasedn = NULL;
3773 	authority.cred.unix_cred.passwd = NULL;
3774 	authority.cred.unix_cred.userID = NULL;
3775 	authority.auth.type = NS_LDAP_AUTH_SIMPLE;
3776 
3777 	while ((c = getopt(argc, argv, "cdhvpf:D:w:b:a:")) != EOF) {
3778 		switch (c) {
3779 		case 'd':
3780 			if (op)
3781 				usage("no other option should be specified");
3782 			op = OP_DUMP;
3783 			break;
3784 		case 'c':
3785 			continue_onerror = 1;
3786 			break;
3787 		case 'v':
3788 			flags |= F_VERBOSE;
3789 			break;
3790 		case 'p':
3791 			flags |= F_PASSWD;
3792 			break;
3793 		case 'f':
3794 			etcfile = optarg;
3795 			break;
3796 		case 'D':
3797 			authority.cred.unix_cred.userID = strdup(optarg);
3798 			break;
3799 		case 'w':
3800 			authority.cred.unix_cred.passwd = strdup(optarg);
3801 			break;
3802 		case 'b':
3803 			inputbasedn = strdup(optarg);
3804 			break;
3805 		case 'a':
3806 			authmech = strdup(optarg);
3807 			break;
3808 
3809 		default:
3810 			usage(gettext("Invalid option"));
3811 		}
3812 	}
3813 
3814 
3815 	if (authority.cred.unix_cred.userID == NULL && op != OP_DUMP) {
3816 	    /* This is not an optional parameter. Exit */
3817 		(void) fprintf(stderr,
3818 			gettext("Distinguished Name to bind to directory"
3819 				" must be specified. use option -D.\n"));
3820 		exit(1);
3821 	}
3822 
3823 	if (authority.cred.unix_cred.passwd == NULL && op != OP_DUMP) {
3824 		/* If password is not specified, then prompt user for it. */
3825 		password = getpassphrase("Enter password:");
3826 		(void) strcpy(ps, password);
3827 		authority.cred.unix_cred.passwd = strdup(ps);
3828 	}
3829 
3830 	if (authmech != NULL) {
3831 		if (strcasecmp(authmech, "simple") == 0) {
3832 		authority.auth.type = NS_LDAP_AUTH_SIMPLE;
3833 		authority.auth.tlstype = NS_LDAP_TLS_NONE;
3834 		authority.auth.saslmech = NS_LDAP_SASL_NONE;
3835 		authority.auth.saslopt = NS_LDAP_SASLOPT_NONE;
3836 		supportedauth = 1;
3837 		}
3838 		if (strcasecmp(authmech, "sasl/CRAM-MD5") == 0) {
3839 		authority.auth.type = NS_LDAP_AUTH_SASL;
3840 		authority.auth.tlstype = NS_LDAP_TLS_SASL;
3841 		authority.auth.saslmech = NS_LDAP_SASL_CRAM_MD5;
3842 		authority.auth.saslopt = NS_LDAP_SASLOPT_NONE;
3843 		supportedauth = 1;
3844 		}
3845 		if (strcasecmp(authmech, "sasl/DIGEST-MD5") == 0) {
3846 		authority.auth.type = NS_LDAP_AUTH_SASL;
3847 		authority.auth.tlstype = NS_LDAP_TLS_SASL;
3848 		authority.auth.saslmech = NS_LDAP_SASL_DIGEST_MD5;
3849 		authority.auth.saslopt = NS_LDAP_SASLOPT_NONE;
3850 		supportedauth = 1;
3851 		}
3852 		if (strcasecmp(authmech, "tls:simple") == 0) {
3853 		authority.auth.type = NS_LDAP_AUTH_TLS;
3854 		authority.auth.tlstype = NS_LDAP_TLS_SIMPLE;
3855 		authority.auth.saslmech = NS_LDAP_SASL_NONE;
3856 		authority.auth.saslopt = NS_LDAP_SASLOPT_NONE;
3857 		supportedauth = 1;
3858 		}
3859 		if (strcasecmp(authmech, "tls:sasl/CRAM-MD5") == 0) {
3860 		authority.auth.type = NS_LDAP_AUTH_TLS;
3861 		authority.auth.tlstype = NS_LDAP_TLS_SASL;
3862 		authority.auth.saslmech = NS_LDAP_SASL_CRAM_MD5;
3863 		authority.auth.saslopt = NS_LDAP_SASLOPT_NONE;
3864 		supportedauth = 1;
3865 		}
3866 		if (strcasecmp(authmech, "tls:sasl/DIGEST-MD5") == 0) {
3867 		authority.auth.type = NS_LDAP_AUTH_TLS;
3868 		authority.auth.tlstype = NS_LDAP_TLS_SASL;
3869 		authority.auth.saslmech = NS_LDAP_SASL_DIGEST_MD5;
3870 		authority.auth.saslopt = NS_LDAP_SASLOPT_NONE;
3871 		supportedauth = 1;
3872 		}
3873 		if (!supportedauth) {
3874 			(void) fprintf(stderr,
3875 			gettext("Invalid authentication method specified"));
3876 			exit(1);
3877 		}
3878 	}
3879 
3880 	if (authmech == NULL) {
3881 		ldaprc = __ns_ldap_getParam(NS_LDAP_AUTH_P, (void ***)&authpp,
3882 			&errorp);
3883 		if (ldaprc != NS_LDAP_SUCCESS ||
3884 		    (authpp == NULL && op != OP_DUMP)) {
3885 			(void) fprintf(stderr,
3886 			    gettext("No legal authentication method "
3887 			    "configured.\n"));
3888 			(void) fprintf(stderr,
3889 			    gettext("Provide a legal authentication method "
3890 			    "using -a option\n"));
3891 			exit(1);
3892 		}
3893 
3894 		/* Use the first authentication method which is not none */
3895 		for (app = authpp; *app; app++) {
3896 			authp = *app;
3897 			if (authp->type != NS_LDAP_AUTH_NONE) {
3898 				authstried++;
3899 				authority.auth.type = authp->type;
3900 				authority.auth.tlstype = authp->tlstype;
3901 				authority.auth.saslmech = authp->saslmech;
3902 				authority.auth.saslopt = authp->saslopt;
3903 				break;
3904 			}
3905 		}
3906 		if (authstried == 0 && op != OP_DUMP) {
3907 			(void) fprintf(stderr,
3908 			gettext("No legal authentication method configured.\n"
3909 				"Provide a legal authentication method using "
3910 				"-a option"));
3911 			exit(1);
3912 		}
3913 	}
3914 
3915 	ttype = argv[optind++];
3916 
3917 	if (ttype == NULL) {
3918 		usage(gettext("No database type specified"));
3919 		exit(1);
3920 	}
3921 
3922 	if (strncasecmp(ttype, "automount", 9) == 0) {
3923 		(void) fprintf(stderr,
3924 		    gettext("automount is not a valid service for ldapaddent.\n"
3925 		    "Please use auto_*.\n"
3926 		    "e.g.  auto_home, auto_ws etc.\n "));
3927 		exit(1);
3928 	}
3929 
3930 	for (tt = ttypelist; tt->ttype; tt++) {
3931 		if (strcmp(tt->ttype, ttype) == 0)
3932 			break;
3933 		if (strcmp(tt->ttype, NS_LDAP_TYPE_AUTOMOUNT) == 0 &&
3934 		    strncmp(ttype, NS_LDAP_TYPE_AUTOMOUNT,
3935 		    sizeof (NS_LDAP_TYPE_AUTOMOUNT) - 1) == 0)
3936 			break;
3937 	}
3938 
3939 	if (tt->ttype == 0) {
3940 		(void) fprintf(stderr,
3941 		    gettext("database %s not supported;"
3942 		    " supported databases are:\n"), ttype);
3943 		for (tt = ttypelist; tt->ttype; tt++)
3944 			(void) fprintf(stderr, gettext("\t%s\n"), tt->ttype);
3945 		exit(1);
3946 	}
3947 
3948 	if (flags & F_VERBOSE)
3949 		(void) fprintf(stdout, gettext("SERVICE = %s\n"), tt->ttype);
3950 
3951 	databasetype = ttype;
3952 
3953 	if (strcmp(tt->ttype, NS_LDAP_TYPE_AUTOMOUNT) == 0) {
3954 		paramVal = NULL;
3955 		errorp = NULL;
3956 		rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P, &paramVal,
3957 			&errorp);
3958 		if (paramVal && *paramVal &&
3959 			strcasecmp(*paramVal, NS_LDAP_VERSION_1) == 0)
3960 			version1 = 1;
3961 		if (paramVal)
3962 			(void) __ns_ldap_freeParam(&paramVal);
3963 		if (errorp)
3964 			(void) __ns_ldap_freeError(&errorp);
3965 	}
3966 
3967 	/* Check if the container exists in first place */
3968 	(void) strcpy(&filter[0], "(objectclass=*)");
3969 
3970 	rc = __ns_ldap_list(databasetype, filter, NULL, (const char **)NULL,
3971 	    NULL, NS_LDAP_SCOPE_BASE, &resultp, &errorp, NULL, NULL);
3972 
3973 	/* create a container for auto_* if it does not exist already */
3974 	if ((rc == NS_LDAP_NOTFOUND) && (op == OP_ADD) &&
3975 	    (strcmp(tt->ttype, NS_LDAP_TYPE_AUTOMOUNT) == 0)) {
3976 		static	char *oclist[] = {NULL, "top", NULL};
3977 		if (version1)
3978 			oclist[0] = "nisMap";
3979 		else
3980 			oclist[0] = "automountMap";
3981 		e = __s_mk_entry(oclist, 3);
3982 		if (e == NULL) {
3983 			(void) fprintf(stderr,
3984 			    gettext("internal memory allocation error.\n"));
3985 			exit(1);
3986 		}
3987 		if (__s_add_attr(e,
3988 		    version1 ? "nisMapName" : "automountMapName",
3989 		    databasetype) != NS_LDAP_SUCCESS) {
3990 			(void) fprintf(stderr,
3991 			    gettext("internal memory allocation error.\n"));
3992 			ldap_freeEntry(e);
3993 			exit(1);
3994 		}
3995 
3996 		if (inputbasedn == NULL) {
3997 			if (get_basedn(databasetype, &inputbasedn) !=
3998 			    NS_LDAP_SUCCESS) {
3999 				(void) fprintf(stderr,
4000 				    gettext("Could not obtain basedn\n"));
4001 				ldap_freeEntry(e);
4002 				exit(1);
4003 			}
4004 		}
4005 		if (__ns_ldap_addEntry(databasetype, inputbasedn, e,
4006 		    &authority, flag, &errorp) != NS_LDAP_SUCCESS) {
4007 			(void) fprintf(stderr,
4008 			    gettext("Could not create container for %s\n"),
4009 			    databasetype);
4010 			ldap_freeEntry(e);
4011 		}
4012 	} else if (strcmp(databasetype, "publickey") != 0) {
4013 		if (rc == NS_LDAP_NOTFOUND) {
4014 			(void) fprintf(stderr,
4015 			    gettext("Container %s does not exist\n"),
4016 			    databasetype);
4017 			exit(1);
4018 		}
4019 	}
4020 
4021 	if (op == OP_DUMP) {
4022 		if (strcmp(databasetype, "publickey") == 0) {
4023 			dumptable("hosts");
4024 			dumptable("passwd");
4025 		} else {
4026 			dumptable(databasetype);
4027 		}
4028 		exit(exit_val);
4029 	}
4030 
4031 	if (etcfile) {
4032 		if ((etcf = fopen(etcfile, "r")) == 0) {
4033 			(void) fprintf(stderr,
4034 			    gettext("can't open file %s\n"), etcfile);
4035 			exit(1);
4036 		}
4037 	} else {
4038 		etcfile = "stdin";
4039 		etcf = stdin;
4040 	}
4041 
4042 	if (op == OP_ADD) {
4043 		(void) addfile();
4044 		(void) fprintf(stdout, gettext("%d entries added\n"), nent_add);
4045 	}
4046 
4047 	/* exit() -> return for make lint */
4048 	return (exit_val);
4049 }
4050 
4051 
4052 /*
4053  * This is called when service == auto_*.
4054  * It calls __ns_ldap_getSearchDescriptors
4055  * to generate the dn from SSD's base dn.
4056  * If there is no SSD available,
4057  * default base dn will be used
4058  * Only the first baseDN in the SSD is used
4059  */
4060 
4061 static int get_basedn(char *service, char **basedn) {
4062 	int rc = NS_LDAP_SUCCESS;
4063 	char *dn = NULL;
4064 	ns_ldap_search_desc_t **desc = NULL;
4065 	ns_ldap_error_t *errp = NULL;
4066 	void		**paramVal = NULL;
4067 	int		prepend_automountmapname = FALSE;
4068 
4069 	/*
4070 	 * Get auto_* SSD first
4071 	 */
4072 
4073 	if ((rc = __ns_ldap_getSearchDescriptors(
4074 			(const char *) service,
4075 			&desc, &errp))  == NS_LDAP_SUCCESS &&
4076 		desc != NULL) {
4077 
4078 		if (desc[0] != NULL && desc[0]->basedn != NULL) {
4079 			dn = strdup(desc[0]->basedn);
4080 			if (dn == NULL) {
4081 				(void) __ns_ldap_freeSearchDescriptors
4082 						(&desc);
4083 				return (NS_LDAP_MEMORY);
4084 			}
4085 		}
4086 	}
4087 
4088 	/* clean up */
4089 	if (desc) (void) __ns_ldap_freeSearchDescriptors(&desc);
4090 	if (errp) (void) __ns_ldap_freeError(&errp);
4091 
4092 	/*
4093 	 * If no dn is duplicated from auto_* SSD, try automount SSD
4094 	 */
4095 	if (dn == NULL) {
4096 		if ((rc = __ns_ldap_getSearchDescriptors(
4097 				"automount", &desc, &errp))
4098 				== NS_LDAP_SUCCESS && desc != NULL) {
4099 
4100 			if (desc[0] != NULL && desc[0]->basedn != NULL) {
4101 				dn = strdup(desc[0]->basedn);
4102 				if (dn == NULL) {
4103 					(void) __ns_ldap_freeSearchDescriptors
4104 							(&desc);
4105 					return (NS_LDAP_MEMORY);
4106 				}
4107 				prepend_automountmapname = TRUE;
4108 			}
4109 		}
4110 		/* clean up */
4111 		if (desc) (void) __ns_ldap_freeSearchDescriptors(&desc);
4112 		if (errp) (void) __ns_ldap_freeError(&errp);
4113 	}
4114 
4115 	/*
4116 	 * If no dn is duplicated from auto_* or automount SSD,
4117 	 * use default DN
4118 	 */
4119 
4120 	if (dn == NULL) {
4121 		if ((rc = __ns_ldap_getParam(NS_LDAP_SEARCH_BASEDN_P,
4122 			&paramVal, &errp)) == NS_LDAP_SUCCESS) {
4123 			dn = strdup((char *)paramVal[0]);
4124 			if (dn == NULL) {
4125 				(void) __ns_ldap_freeParam(&paramVal);
4126 				return (NS_LDAP_MEMORY);
4127 			}
4128 			prepend_automountmapname = TRUE;
4129 		}
4130 		if (paramVal) (void) __ns_ldap_freeParam(&paramVal);
4131 		if (errp) (void) __ns_ldap_freeError(&errp);
4132 	}
4133 
4134 
4135 	if (dn == NULL) {
4136 		return (NS_LDAP_OP_FAILED);
4137 	} else {
4138 		/*
4139 		 * If dn is duplicated from
4140 		 * automount SSD basedn or
4141 		 * default base dn
4142 		 * then prepend automountMapName=auto_xxx
4143 		 */
4144 		if (prepend_automountmapname)
4145 			rc = __s_api_prepend_automountmapname_to_dn(
4146 				service, &dn, &errp);
4147 
4148 		if (rc != NS_LDAP_SUCCESS) {
4149 			(void) __ns_ldap_freeError(&errp);
4150 			free(dn);
4151 			return (rc);
4152 		}
4153 
4154 		*basedn = dn;
4155 
4156 		return (NS_LDAP_SUCCESS);
4157 	}
4158 }
4159