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