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