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