1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <sys/types.h>
31 #include <stdlib.h>
32 #include <libintl.h>
33 
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <strings.h>
39 #include <lber.h>
40 #include <ldap.h>
41 #include <syslog.h>
42 
43 #include "ns_sldap.h"
44 #include "ns_internal.h"
45 
46 /* Additional headers for addTypedEntry Conversion routines */
47 #include <pwd.h>
48 #include <shadow.h>
49 #include <grp.h>
50 #include <netinet/in.h>
51 #include <arpa/inet.h>
52 #include <netdb.h>
53 #include <rpc/rpcent.h>
54 #include <auth_attr.h>
55 #include <exec_attr.h>
56 #include <prof_attr.h>
57 #include <user_attr.h>
58 #include <bsm/libbsm.h>
59 
60 
61 /*
62  * If the rdn is a mapped attr:
63  * 	return NS_LDAP_SUCCESS and a new_dn.
64  * If no mapped attr is found in the rdn:
65  * 	return NS_LDAP_SUCCESS and *new_dn == NULL
66  * For example:
67  *  service = abc
68  *  dn =  cn=foo,dc=bar,dc=com
69  *  attributeMapping: abc:cn=sn
70  * Then:
71  *  new_dn = sn=foo,dc=bar,dc=com
72  *
73  */
74 static int
75 replace_mapped_attr_in_dn(
76 	const char *service, const char *dn, char **new_dn)
77 {
78 	char	**mappedattr;
79 	char	**dnArray = NULL;
80 	char	*rservice;
81 	char	*cur = NULL;
82 	int	len = 0, orig_len = 0, mapped_len = 0;
83 	int	dn_len = 0;
84 
85 	*new_dn = NULL;
86 
87 	/*
88 	 * seperate dn into individual componets
89 	 * e.g.
90 	 * "automountKey=user_01" , "automountMapName_test=auto_home", ...
91 	 */
92 	dnArray = ldap_explode_dn(dn, 0);
93 	if (!dnArray || !*dnArray)
94 		return (NS_LDAP_INVALID_PARAM);
95 
96 	cur = strchr(dnArray[0], '=');
97 	if (!cur) {
98 		__s_api_free2dArray(dnArray);
99 		return (NS_LDAP_INVALID_PARAM);
100 	}
101 	*cur = '\0';
102 
103 	/* we only check schema mapping for automount, not for auto_* */
104 	if (strncasecmp(service, NS_LDAP_TYPE_AUTOMOUNT,
105 	    sizeof (NS_LDAP_TYPE_AUTOMOUNT) - 1) == 0)
106 		rservice = "automount";
107 	else
108 		rservice = (char *)service;
109 
110 	mappedattr = __ns_ldap_getMappedAttributes(rservice, dnArray[0]);
111 	if (!mappedattr || !mappedattr[0]) {
112 		__s_api_free2dArray(dnArray);
113 		if (mappedattr)
114 			__s_api_free2dArray(mappedattr);
115 		return (NS_LDAP_SUCCESS);
116 	}
117 	orig_len = strlen(dnArray[0]);
118 
119 	/*
120 	 * The new length is *dn length + (difference between
121 	 * orig attr and mapped attr) + 1 ;
122 	 * e.g.
123 	 * automountKey=aa,automountMapName=auto_home,dc=foo,dc=com
124 	 * ==>
125 	 * cn=aa,automountMapName=auto_home,dc=foo,dc=com
126 	 */
127 	mapped_len = strlen(mappedattr[0]);
128 	dn_len = strlen(dn);
129 	len = dn_len - orig_len + mapped_len + 1;
130 	*new_dn = (char *)calloc(1, len);
131 	if (*new_dn == NULL) {
132 		__s_api_free2dArray(dnArray);
133 		__s_api_free2dArray(mappedattr);
134 		return (NS_LDAP_MEMORY);
135 	}
136 
137 	(void) snprintf(*new_dn, len, "%s=%s", mappedattr[0], dn + orig_len +1);
138 	__s_api_free2dArray(dnArray);
139 	__s_api_free2dArray(mappedattr);
140 
141 	return (NS_LDAP_SUCCESS);
142 }
143 
144 
145 /*
146  * The following function is only used by the
147  * "gecos" 1 to N attribute mapping code. It expects
148  * and handle only one data/length pair.
149  */
150 static int
151 init_bval_mod(
152 	LDAPMod *mod,
153 	int	mop,
154 	char	*mtype,
155 	char	*mvptr,
156 	int 	mvlen)
157 {
158 
159 	struct berval	**bmodval;
160 
161 	/* dup attribute name */
162 	mod->mod_type = strdup(mtype);
163 	if (mod->mod_type == NULL)
164 		return (-1);
165 
166 	/*
167 	 * assume single value,
168 	 * since only one value/length pair passed in
169 	 */
170 	bmodval = (struct berval **)calloc(2,
171 			sizeof (struct berval *));
172 	if (bmodval == NULL) {
173 		free(mod->mod_type);
174 		mod->mod_type = NULL;
175 		return	(-1);
176 	}
177 	bmodval[0] = (struct berval *)calloc(1,
178 			sizeof (struct berval));
179 	if (bmodval[0] == NULL) {
180 		free(mod->mod_type);
181 		mod->mod_type = NULL;
182 		free(bmodval);
183 		return	(-1);
184 	}
185 
186 	/* set pointer to data */
187 	bmodval[0]->bv_val = mvptr;
188 
189 	/* set length */
190 	bmodval[0]->bv_len = mvlen;
191 
192 	/*
193 	 * turn on the BVALUE bit to indicate
194 	 * that the length of data is supplied
195 	 */
196 	mod->mod_op = mop | LDAP_MOD_BVALUES;
197 
198 	mod->mod_bvalues = bmodval;
199 
200 	return	(0);
201 }
202 
203 static void
204 freeModList(LDAPMod **mods)
205 {
206 	int i, j;
207 	int name_is_oc;
208 
209 	if (mods == NULL)
210 		return;
211 
212 	for (i = 0; mods[i]; i++) {
213 
214 		/* free attribute name */
215 		name_is_oc = FALSE;
216 		if (mods[i]->mod_type) {
217 			if (strcasecmp(mods[i]->mod_type,
218 				"objectclass") == 0)
219 				name_is_oc = TRUE;
220 			free(mods[i]->mod_type);
221 		}
222 
223 		if (mods[i]->mod_bvalues == NULL)
224 			continue;
225 		/*
226 		 * LDAP_MOD_BVALUES is only set by
227 		 * the "gecos" 1 to N attribute mapping
228 		 * code, and the attribute is single valued.
229 		 */
230 		if (mods[i]->mod_op & LDAP_MOD_BVALUES) {
231 			if (mods[i]->mod_bvalues[0])
232 				free(mods[i]->mod_bvalues[0]);
233 		} else {
234 			if (name_is_oc) {
235 				/*
236 				 * only values for the "objectclass"
237 				 * were dupped using strdup.
238 				 * other attribute values were
239 				 * not dupped, but via pointer
240 				 * assignment. So here the
241 				 * values for "objectclass"
242 				 * is freed one by one,
243 				 * but the values for other
244 				 * attributes need not be freed.
245 				 */
246 				for (j = 0; mods[i]->mod_values[j]; j++)
247 					free(mods[i]->mod_values[j]);
248 			}
249 
250 		}
251 		free(mods[i]->mod_bvalues);
252 	}
253 
254 	/* modlist */
255 	free((char *)(mods[0]));
256 	free(mods);
257 }
258 
259 static LDAPMod **
260 __s_api_makeModListCount(
261 	const char *service,
262 	const ns_ldap_attr_t * const *attr,
263 	const int mod_op,
264 	const int count,
265 	const int flags)
266 {
267 	LDAPMod		**mods, *modlist;
268 	char		**modval;
269 	char		**mapping;
270 	int		i;
271 	int		j;
272 	int		k, rc, vlen;
273 	char		*c, *comma1 = NULL, *comma2 = NULL;
274 	int		schema_mapping_existed = FALSE;
275 	int		auto_service = FALSE;
276 
277 
278 	/*
279 	 * add 2 for "gecos" 1 to up to 3 attribute mapping
280 	 */
281 	mods = (LDAPMod **)calloc((count + 3), sizeof (LDAPMod *));
282 	if (mods == NULL) {
283 		return (NULL);
284 	}
285 	/*
286 	 * add 2 for "gecos" 1 to up to 3 attribute mapping
287 	 */
288 	modlist = (LDAPMod *)calloc(count + 2, sizeof (LDAPMod));
289 	if (modlist == NULL) {
290 		free(mods);
291 		return (NULL);
292 	}
293 
294 	if (service != NULL && strncasecmp(service, NS_LDAP_TYPE_AUTOMOUNT,
295 	    sizeof (NS_LDAP_TYPE_AUTOMOUNT) - 1) == 0)
296 		auto_service = TRUE;
297 
298 	/*
299 	 * see if schema mapping existed for the given service
300 	 */
301 	mapping = __ns_ldap_getOrigAttribute(service,
302 	    NS_HASH_SCHEMA_MAPPING_EXISTED);
303 	if (mapping) {
304 		schema_mapping_existed = TRUE;
305 		__s_api_free2dArray(mapping);
306 		mapping = NULL;
307 	}
308 
309 	for (i = 0, k = 0; k < count && attr[k] != NULL; i++, k++) {
310 		mods[i] = &modlist[i];
311 		mods[i]->mod_op = mod_op;
312 		/*
313 		 * Perform attribute mapping if necessary.
314 		 */
315 		if (schema_mapping_existed &&
316 			(flags & NS_LDAP_NOMAP) == 0) {
317 			mapping = __ns_ldap_getMappedAttributes(service,
318 			    attr[k]->attrname);
319 		} else
320 			mapping = NULL;
321 
322 		if (mapping == NULL && auto_service &&
323 		    (flags & NS_LDAP_NOMAP) == 0) {
324 			/*
325 			 * if service == auto_xxx and
326 			 * no mapped attribute is found
327 			 * and NS_LDAP_NOMAP is not set
328 			 * then try automount's mapped attribute
329 			 */
330 			mapping = __ns_ldap_getMappedAttributes("automount",
331 			    attr[k]->attrname);
332 		}
333 
334 		if (mapping == NULL) {
335 		    mods[i]->mod_type = strdup(attr[k]->attrname);
336 		    if (mods[i]->mod_type == NULL) {
337 			goto free_memory;
338 		    }
339 		} else {
340 			/*
341 			 * 1 to N attribute mapping is only done for "gecos",
342 			 * and only 1 to 3 mapping.
343 			 * nine cases here:
344 			 *
345 			 * A. attrMap=passwd:gecos=a
346 			 *    1. gecos="xx,yy,zz" -> a="xx,yy,zz"
347 			 *    2. gecos="xx,yy" -> a="xx,yy"
348 			 *    3. gecos="xx" -> a="xx"
349 			 *
350 			 * B. attrMap=passwd:gecos=a b
351 			 *    4. gecos="xx,yy,zz" -> a="xx" b="yy,zz"
352 			 *    5. gecos="xx,yy" -> a="xx" b="yy"
353 			 *    6. gecos="xx" -> a="xx"
354 			 *
355 			 * C. attrMap=passwd:gecos=a b c
356 			 *    7. gecos="xx,yy,zz" -> a="xx" b="yy" c="zz"
357 			 *    8. gecos="xx,yy" -> a="xx" b="yy"
358 			 *    9. gecos="xx" -> a="xx"
359 			 *
360 			 * This can be grouped as:
361 			 *
362 			 * c1 cases: 1,2,3,6,9
363 			 *    if ((attrMap=passwd:gecos=a) ||
364 			 *		(no "," in gecos value))
365 			 *	same as other no-mapping attributes,
366 			 *	no special processing needed
367 			 *    else
368 			 *
369 			 * c2 cases: 4,5,8
370 			 *    if ((attrMap=passwd:gecos=a b) ||
371 			 *	(only one "," in gecos value))
372 			 *	a=xx b=yy[,...]
373 			 *    else
374 			 *
375 			 * c3 case: 7
376 			 *    a=xx b=yy c=...
377 			 *
378 			 * notes: in case c2 and c3, ... could still contain ","
379 			 */
380 		    if (strcasecmp(service, "passwd") == 0 &&
381 			strcasecmp(attr[k]->attrname, "gecos") == 0 &&
382 			mapping[1] && attr[k]->attrvalue[0] &&
383 			(comma1 = strchr(attr[k]->attrvalue[0],
384 			COMMATOK)) != NULL) {
385 
386 			/* is there a second comma? */
387 			if (*(comma1 + 1) != '\0')
388 				comma2 = strchr(comma1 + 1, COMMATOK);
389 
390 			/*
391 			 * Process case c2 or c3.
392 			 * case c2: mapped to two attributes or just
393 			 * one comma
394 			 */
395 			if (mapping[2] == NULL ||
396 				comma2 == NULL) {
397 				/* case c2 */
398 
399 				/*
400 				 * int mod structure for the first attribute
401 				 */
402 				vlen = comma1 - attr[k]->attrvalue[0];
403 				c = attr[k]->attrvalue[0];
404 
405 				if (vlen > 0 && c) {
406 					rc = init_bval_mod(mods[i], mod_op,
407 						mapping[0], c, vlen);
408 					if (rc != 0)
409 						goto free_memory;
410 				} else {
411 					/* don't leave a hole in mods array */
412 					mods[i] = NULL;
413 					i--;
414 				}
415 
416 
417 				/*
418 				 * init mod structure for the 2nd attribute
419 				 */
420 				if (*(comma1 + 1) == '\0') {
421 					__s_api_free2dArray(mapping);
422 					mapping = NULL;
423 					continue;
424 				}
425 
426 				i++;
427 				mods[i] = &modlist[i];
428 
429 				/*
430 				 * get pointer to data.
431 				 * Skip leading spaces.
432 				 */
433 				for (c = comma1 + 1; *c == SPACETOK; c++);
434 
435 				/* get data length */
436 				vlen = strlen(attr[k]->attrvalue[0]) -
437 					(c - attr[k]->attrvalue[0]);
438 
439 				if (vlen > 0 && c) {
440 					rc = init_bval_mod(mods[i], mod_op,
441 						mapping[1], c, vlen);
442 					if (rc != 0)
443 						goto free_memory;
444 				} else {
445 					/* don't leave a hole in mods array */
446 					mods[i] = NULL;
447 					i--;
448 				}
449 
450 				/* done with the mapping array */
451 				__s_api_free2dArray(mapping);
452 				mapping = NULL;
453 
454 				continue;
455 			} else {
456 				/* case c3 */
457 
458 				/*
459 				 * int mod structure for the first attribute
460 				 */
461 				vlen = comma1 - attr[k]->attrvalue[0];
462 				c = attr[k]->attrvalue[0];
463 
464 				if (vlen > 0 && c) {
465 					rc = init_bval_mod(mods[i], mod_op,
466 						mapping[0], c, vlen);
467 					if (rc != 0)
468 						goto free_memory;
469 				} else {
470 					/* don't leave a hole in mods array */
471 					mods[i] = NULL;
472 					i--;
473 				}
474 
475 				/*
476 				 * init mod structure for the 2nd attribute
477 				 */
478 				i++;
479 				mods[i] = &modlist[i];
480 
481 				/*
482 				 * get pointer to data.
483 				 * Skip leading spaces.
484 				 */
485 				for (c = comma1 + 1; *c == SPACETOK; c++);
486 
487 				/* get data length */
488 				vlen = comma2 - c;
489 
490 				if (vlen > 0 && c) {
491 					rc = init_bval_mod(mods[i], mod_op,
492 						mapping[1], c, vlen);
493 					if (rc != 0)
494 						goto free_memory;
495 				} else {
496 					/* don't leave a hole in mods array */
497 					mods[i] = NULL;
498 					i--;
499 				}
500 
501 				/*
502 				 * init mod structure for the 3rd attribute
503 				 */
504 				if (*(comma2 + 1) == '\0') {
505 					__s_api_free2dArray(mapping);
506 					mapping = NULL;
507 					continue;
508 				}
509 
510 				i++;
511 				mods[i] = &modlist[i];
512 				/*
513 				 * get pointer to data.
514 				 * Skip leading spaces.
515 				 */
516 				for (c = comma2 + 1; *c == SPACETOK; c++);
517 
518 				/* get data length */
519 				vlen = strlen(attr[k]->attrvalue[0]) -
520 					(c - attr[k]->attrvalue[0]);
521 
522 				if (vlen > 0 && c) {
523 					rc = init_bval_mod(mods[i], mod_op,
524 						mapping[2], c, vlen);
525 					if (rc != 0)
526 						goto free_memory;
527 				} else {
528 					/* don't leave a hole in mods array */
529 					mods[i] = NULL;
530 					i--;
531 				}
532 
533 				/* done with the mapping array */
534 				__s_api_free2dArray(mapping);
535 				mapping = NULL;
536 
537 				continue;
538 			}
539 		    }
540 
541 		    /* case c1 */
542 		    mods[i]->mod_type = strdup(mapping[0]);
543 		    if (mods[i]->mod_type == NULL) {
544 				goto free_memory;
545 		    }
546 		    __s_api_free2dArray(mapping);
547 		    mapping = NULL;
548 		}
549 
550 		modval = (char **)calloc(attr[k]->value_count+1,
551 				sizeof (char *));
552 		if (modval == NULL)
553 			goto free_memory;
554 		/*
555 		 * Perform objectclass mapping.
556 		 * Note that the values for the "objectclass" attribute
557 		 * will be dupped using strdup. Values for other
558 		 * attributes will be referenced via pointer
559 		 * assignments.
560 		 */
561 		if (strcasecmp(mods[i]->mod_type, "objectclass") == 0) {
562 			for (j = 0; j < attr[k]->value_count; j++) {
563 				if (schema_mapping_existed &&
564 					(flags & NS_LDAP_NOMAP) == 0)
565 					mapping =
566 					__ns_ldap_getMappedObjectClass(
567 					service, attr[k]->attrvalue[j]);
568 				else
569 					mapping = NULL;
570 
571 				if (mapping == NULL && auto_service &&
572 					(flags & NS_LDAP_NOMAP) == 0)
573 					/*
574 					 * if service == auto_xxx and
575 					 * no mapped objectclass is found
576 					 * then try automount
577 					 */
578 					mapping =
579 					__ns_ldap_getMappedObjectClass(
580 					"automount", attr[k]->attrvalue[j]);
581 
582 				if (mapping && mapping[0]) {
583 					/* assume single mapping */
584 					modval[j] = strdup(mapping[0]);
585 				} else {
586 					modval[j] = strdup(attr[k]->
587 							attrvalue[j]);
588 				}
589 				if (modval[j] == NULL)
590 					goto free_memory;
591 			}
592 		} else {
593 			for (j = 0; j < attr[k]->value_count; j++) {
594 				/* ASSIGN NOT COPY */
595 				modval[j] = attr[k]->attrvalue[j];
596 			}
597 		}
598 		mods[i]->mod_values = modval;
599 	}
600 
601 	return (mods);
602 
603 free_memory:
604 	freeModList(mods);
605 	if (mapping)
606 	__s_api_free2dArray(mapping);
607 
608 	return (NULL);
609 
610 }
611 
612 static LDAPMod **
613 __s_api_makeModList(
614 	const char *service,
615 	const ns_ldap_attr_t * const *attr,
616 	const int mod_op,
617 	const int flags)
618 {
619 	ns_ldap_attr_t	**aptr = (ns_ldap_attr_t **)attr;
620 	int		count = 0;
621 
622 	if (aptr == NULL)
623 		return (NULL);
624 
625 	/* count number of attributes */
626 	while (*aptr++)
627 		count++;
628 
629 	return (__s_api_makeModListCount(service, attr, mod_op, count, flags));
630 }
631 
632 static void
633 __s_cvt_freeEntryRdn(ns_ldap_entry_t **entry, char **rdn)
634 {
635 	if (*entry != NULL) {
636 		__ns_ldap_freeEntry(*entry);
637 		*entry = NULL;
638 	}
639 	if (*rdn != NULL) {
640 		free(*rdn);
641 		*rdn = NULL;
642 	}
643 }
644 
645 /*
646  * This state machine performs one or more LDAP add/delete/modify
647  * operations to configured LDAP servers.
648  */
649 static int
650 write_state_machine(
651 	int 		ldap_op,
652 	char 		*dn,
653 	LDAPMod		**mods,
654 	const ns_cred_t *cred,
655 	const int 	flags,
656 	ns_ldap_error_t ** errorp)
657 {
658 	ConnectionID    connectionId = -1;
659 	Connection	*conp = NULL;
660 	LDAPMessage 	*res;
661 	char		*target_dn = NULL;
662 	char		errstr[MAXERROR];
663 	int		rc = NS_LDAP_SUCCESS;
664 	int		return_rc = NS_LDAP_SUCCESS;
665 	int		followRef = FALSE;
666 	int		target_dn_allocated = FALSE;
667 	int		len;
668 	int		msgid;
669 	int		Errno;
670 	int		always = 1;
671 	char		*err, *errmsg = NULL;
672 	/* referrals returned by the LDAP operation */
673 	char		**referrals = NULL;
674 	/*
675 	 * list of referrals used by the state machine, built from
676 	 * the referrals variable above
677 	 */
678 	ns_referral_info_t *ref_list = NULL;
679 	/* current referral */
680 	ns_referral_info_t *current_ref = NULL;
681 	ns_write_state_t state = W_INIT, new_state, err_state = W_INIT;
682 	int		do_not_fail_if_new_pwd_reqd = 0;
683 	ns_ldap_passwd_status_t	pwd_status = NS_PASSWD_GOOD;
684 	int		passwd_mgmt = 0;
685 	int		i = 0;
686 	int		ldap_error;
687 
688 	while (always) {
689 		switch (state) {
690 		case W_EXIT:
691 			if (connectionId > -1)
692 				DropConnection(connectionId, 0);
693 			if (ref_list)
694 				__s_api_deleteRefInfo(ref_list);
695 			if (target_dn && target_dn_allocated)
696 				free(target_dn);
697 			return (return_rc);
698 		case W_INIT:
699 			/* see if need to follow referrals */
700 			rc = __s_api_toFollowReferrals(flags,
701 				&followRef, errorp);
702 			if (rc != NS_LDAP_SUCCESS) {
703 				return_rc = rc;
704 				new_state = W_ERROR;
705 				break;
706 			}
707 			len = strlen(dn);
708 			if (dn[len-1] == COMMATOK)
709 				rc = __s_api_append_default_basedn(
710 					dn, &target_dn,
711 					&target_dn_allocated,
712 					errorp);
713 			else
714 				target_dn = dn;
715 			if (rc != NS_LDAP_SUCCESS) {
716 				return_rc = rc;
717 				new_state = W_ERROR;
718 			}
719 			else
720 				new_state = GET_CONNECTION;
721 			break;
722 		case GET_CONNECTION:
723 			rc = __s_api_getConnection(NULL,
724 				flags,
725 				cred,
726 				&connectionId,
727 				&conp,
728 				errorp,
729 				do_not_fail_if_new_pwd_reqd);
730 
731 			/*
732 			 * If password control attached
733 			 * in *errorp,
734 			 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
735 			 * free the error structure (we do not need
736 			 * the password management info).
737 			 * Reset rc to NS_LDAP_SUCCESS.
738 			 */
739 			if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
740 				(void) __ns_ldap_freeError(
741 					errorp);
742 				*errorp = NULL;
743 				rc = NS_LDAP_SUCCESS;
744 			}
745 
746 			if (rc != NS_LDAP_SUCCESS) {
747 				return_rc = rc;
748 				new_state = W_ERROR;
749 				break;
750 			}
751 			if (followRef)
752 				new_state = SELECT_OPERATION_ASYNC;
753 			else
754 				new_state = SELECT_OPERATION_SYNC;
755 			break;
756 		case SELECT_OPERATION_SYNC:
757 			if (ldap_op == LDAP_REQ_ADD)
758 				new_state = DO_ADD_SYNC;
759 			else if (ldap_op == LDAP_REQ_DELETE)
760 				new_state = DO_DELETE_SYNC;
761 			else if (ldap_op == LDAP_REQ_MODIFY)
762 				new_state = DO_MODIFY_SYNC;
763 			break;
764 		case SELECT_OPERATION_ASYNC:
765 			if (ldap_op == LDAP_REQ_ADD)
766 				new_state = DO_ADD_ASYNC;
767 			else if (ldap_op == LDAP_REQ_DELETE)
768 				new_state = DO_DELETE_ASYNC;
769 			else if (ldap_op == LDAP_REQ_MODIFY)
770 				new_state = DO_MODIFY_ASYNC;
771 			break;
772 		case DO_ADD_SYNC:
773 			rc = ldap_add_ext_s(conp->ld, target_dn,
774 				mods, NULL, NULL);
775 			new_state = GET_RESULT_SYNC;
776 			break;
777 		case DO_DELETE_SYNC:
778 			rc = ldap_delete_ext_s(conp->ld, target_dn,
779 				NULL, NULL);
780 			new_state = GET_RESULT_SYNC;
781 			break;
782 		case DO_MODIFY_SYNC:
783 			rc = ldap_modify_ext_s(conp->ld, target_dn,
784 				mods, NULL, NULL);
785 			new_state = GET_RESULT_SYNC;
786 			break;
787 		case DO_ADD_ASYNC:
788 			rc = ldap_add_ext(conp->ld, target_dn,
789 				mods, NULL, NULL, &msgid);
790 			new_state = GET_RESULT_ASYNC;
791 			break;
792 		case DO_DELETE_ASYNC:
793 			rc = ldap_delete_ext(conp->ld, target_dn,
794 				NULL, NULL, &msgid);
795 			new_state = GET_RESULT_ASYNC;
796 			break;
797 		case DO_MODIFY_ASYNC:
798 			rc = ldap_modify_ext(conp->ld, target_dn,
799 				mods, NULL, NULL, &msgid);
800 			new_state = GET_RESULT_ASYNC;
801 			break;
802 		case GET_RESULT_SYNC:
803 			if (rc != LDAP_SUCCESS) {
804 				Errno = rc;
805 				(void) ldap_get_lderrno(conp->ld,
806 					NULL, &errmsg);
807 				/*
808 				 * free errmsg if it is an empty string
809 				 */
810 				if (errmsg && *errmsg == '\0') {
811 					ldap_memfree(errmsg);
812 					errmsg = NULL;
813 				}
814 				new_state = W_LDAP_ERROR;
815 			} else {
816 				return_rc = NS_LDAP_SUCCESS;
817 				new_state = W_EXIT;
818 			}
819 			break;
820 		case GET_RESULT_ASYNC:
821 			rc = ldap_result(conp->ld, msgid, 1,
822 				(struct timeval *)NULL, &res);
823 			/* if no server response, set Errno */
824 			if (rc == -1) {
825 				(void) ldap_get_option(conp->ld,
826 				    LDAP_OPT_ERROR_NUMBER, &Errno);
827 				new_state = W_LDAP_ERROR;
828 				break;
829 			}
830 			if (rc == LDAP_RES_ADD ||
831 				rc == LDAP_RES_MODIFY ||
832 				rc == LDAP_RES_DELETE) {
833 				new_state = PARSE_RESULT;
834 				break;
835 			} else {
836 				return_rc = rc;
837 				new_state = W_ERROR;
838 			}
839 			break;
840 		case PARSE_RESULT:
841 			/*
842 			 * need Errno, referrals, error msg,
843 			 * and the last "1" is to free
844 			 * the result (res)
845 			 */
846 			rc = ldap_parse_result(conp->ld,
847 				res, &Errno,
848 				NULL, &errmsg,
849 				&referrals, NULL, 1);
850 			/*
851 			 * free errmsg if it is an empty string
852 			 */
853 			if (errmsg && *errmsg == '\0') {
854 				ldap_memfree(errmsg);
855 				errmsg = NULL;
856 			}
857 			/*
858 			 * If we received referral data, process
859 			 * it if:
860 			 * - we are configured to follow referrals
861 			 * - and not already in referral mode (to keep
862 			 *   consistency with search_state_machine()
863 			 *   which follows 1 level of referrals only;
864 			 *   see proc_result_referrals() and
865 			 *   proc_search_references().
866 			 */
867 			if (Errno == LDAP_REFERRAL && followRef && !ref_list) {
868 				for (i = 0; referrals[i] != NULL; i++) {
869 					/* add to referral list */
870 					rc = __s_api_addRefInfo(&ref_list,
871 						referrals[i],
872 						NULL, NULL, NULL,
873 						conp->ld);
874 					if (rc != NS_LDAP_SUCCESS) {
875 						__s_api_deleteRefInfo(ref_list);
876 						ref_list = NULL;
877 						break;
878 					}
879 				}
880 				ldap_value_free(referrals);
881 				if (ref_list == NULL) {
882 					if (rc != NS_LDAP_MEMORY)
883 						rc = NS_LDAP_INTERNAL;
884 					return_rc = rc;
885 					new_state = W_ERROR;
886 				} else {
887 					new_state = GET_REFERRAL_CONNECTION;
888 					current_ref = ref_list;
889 				}
890 				if (errmsg) {
891 					ldap_memfree(errmsg);
892 					errmsg = NULL;
893 				}
894 				break;
895 			}
896 			if (Errno != LDAP_SUCCESS) {
897 				new_state = W_LDAP_ERROR;
898 			} else {
899 				return_rc = NS_LDAP_SUCCESS;
900 				new_state = W_EXIT;
901 			}
902 			break;
903 		case GET_REFERRAL_CONNECTION:
904 			/*
905 			 * since we are starting over,
906 			 * discard the old error info
907 			 */
908 			return_rc = NS_LDAP_SUCCESS;
909 			if (*errorp)
910 				(void) __ns_ldap_freeError(errorp);
911 			if (connectionId > -1)
912 				DropConnection(connectionId, 0);
913 			rc = __s_api_getConnection(current_ref->refHost,
914 				0,
915 				cred,
916 				&connectionId,
917 				&conp,
918 				errorp,
919 				do_not_fail_if_new_pwd_reqd);
920 
921 			/*
922 			 * If password control attached
923 			 * in errorp,
924 			 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
925 			 * free the error structure (we do not need
926 			 * the password management info).
927 			 * Reset rc to NS_LDAP_SUCCESS.
928 			 */
929 			if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
930 				(void) __ns_ldap_freeError(
931 					errorp);
932 				*errorp = NULL;
933 				rc = NS_LDAP_SUCCESS;
934 			}
935 
936 			if (rc != NS_LDAP_SUCCESS) {
937 				return_rc = rc;
938 				/*
939 				 * If current referral is not
940 				 * available for some reason,
941 				 * try next referral in the list.
942 				 * Get LDAP error code from errorp.
943 				 */
944 				if (*errorp != NULL) {
945 					ldap_error = (*errorp)->status;
946 					if (ldap_error == LDAP_BUSY ||
947 					    ldap_error == LDAP_UNAVAILABLE ||
948 					    ldap_error ==
949 						LDAP_UNWILLING_TO_PERFORM ||
950 					    ldap_error == LDAP_CONNECT_ERROR ||
951 					    ldap_error == LDAP_SERVER_DOWN) {
952 						current_ref = current_ref->next;
953 						if (current_ref == NULL) {
954 						    /* no more referral */
955 						    /* to follow */
956 						    new_state = W_ERROR;
957 						} else {
958 						    new_state =
959 							GET_REFERRAL_CONNECTION;
960 						}
961 						/*
962 						 * free errorp before going to
963 						 * next referral
964 						 */
965 						(void) __ns_ldap_freeError(
966 							errorp);
967 						*errorp = NULL;
968 						break;
969 					}
970 					/*
971 					 * free errorp before going to W_ERROR
972 					 */
973 					(void) __ns_ldap_freeError(errorp);
974 					*errorp = NULL;
975 				}
976 				/* else, exit */
977 				__s_api_deleteRefInfo(ref_list);
978 				ref_list = NULL;
979 				new_state = W_ERROR;
980 				break;
981 			}
982 			/* target DN may changed due to referrals */
983 			if (current_ref->refDN) {
984 				if (target_dn && target_dn_allocated) {
985 					free(target_dn);
986 					target_dn = NULL;
987 					target_dn_allocated = FALSE;
988 				}
989 				target_dn = current_ref->refDN;
990 			}
991 			new_state = SELECT_OPERATION_SYNC;
992 			break;
993 		case W_LDAP_ERROR:
994 			/*
995 			 * map error code and error message
996 			 * to password status if necessary.
997 			 * This is to see if password updates
998 			 * failed due to password policy or
999 			 * password syntax checking.
1000 			 */
1001 			if (errmsg) {
1002 				/*
1003 				 * check if server supports
1004 				 * password management
1005 				 */
1006 				passwd_mgmt =
1007 					__s_api_contain_passwd_control_oid(
1008 						conp->controls);
1009 					if (passwd_mgmt)
1010 						pwd_status =
1011 						__s_api_set_passwd_status(
1012 						Errno, errmsg);
1013 				ldap_memfree(errmsg);
1014 				errmsg = NULL;
1015 			}
1016 
1017 			(void) sprintf(errstr,
1018 				gettext(ldap_err2string(Errno)));
1019 			err = strdup(errstr);
1020 			if (pwd_status != NS_PASSWD_GOOD) {
1021 				MKERROR_PWD_MGMT(*errorp, Errno, err,
1022 					pwd_status, 0, NULL);
1023 			} else {
1024 				MKERROR(LOG_INFO, *errorp, Errno, err, NULL);
1025 			}
1026 			return_rc = NS_LDAP_INTERNAL;
1027 			new_state = W_EXIT;
1028 			break;
1029 		case W_ERROR:
1030 		default:
1031 			(void) sprintf(errstr,
1032 				gettext("Internal write State machine exit"
1033 					" (state = %d, rc = %d)."),
1034 					err_state, return_rc);
1035 			err = strdup(errstr);
1036 			MKERROR(LOG_WARNING, *errorp, return_rc, err, NULL);
1037 			new_state = W_EXIT;
1038 			break;
1039 		}
1040 
1041 		if (new_state == W_ERROR)
1042 			err_state = state;
1043 		state = new_state;
1044 	}
1045 
1046 	/*
1047 	 * should never be here, the next line is to eliminating
1048 	 * lint message
1049 	 */
1050 	return (NS_LDAP_INTERNAL);
1051 }
1052 
1053 
1054 /*ARGSUSED*/
1055 int
1056 __ns_ldap_addAttr(
1057 	const char *service,
1058 	const char *dn,
1059 	const ns_ldap_attr_t * const *attr,
1060 	const ns_cred_t *cred,
1061 	const int flags,
1062 	ns_ldap_error_t ** errorp)
1063 {
1064 	LDAPMod		**mods;
1065 	int		rc = 0;
1066 
1067 #ifdef DEBUG
1068 	(void) fprintf(stderr, "__ns_ldap_addAttr START\n");
1069 #endif
1070 	*errorp = NULL;
1071 
1072 	/* Sanity check */
1073 	if ((attr == NULL) || (*attr == NULL) ||
1074 	    (dn == NULL) || (cred == NULL))
1075 		return (NS_LDAP_INVALID_PARAM);
1076 
1077 	mods = __s_api_makeModList(service, attr, LDAP_MOD_ADD, flags);
1078 	if (mods == NULL) {
1079 		return (NS_LDAP_MEMORY);
1080 	}
1081 
1082 	rc = write_state_machine(LDAP_REQ_MODIFY,
1083 	    (char *)dn, mods, cred, flags, errorp);
1084 	freeModList(mods);
1085 
1086 	return (rc);
1087 }
1088 
1089 
1090 /*ARGSUSED*/
1091 int
1092 __ns_ldap_delAttr(
1093 	const char *service,
1094 	const char *dn,
1095 	const ns_ldap_attr_t * const *attr,
1096 	const ns_cred_t *cred,
1097 	const int flags,
1098 	ns_ldap_error_t ** errorp)
1099 {
1100 	LDAPMod		**mods;
1101 	int		rc = 0;
1102 
1103 #ifdef DEBUG
1104 	(void) fprintf(stderr, "__ns_ldap_delAttr START\n");
1105 #endif
1106 	*errorp = NULL;
1107 
1108 	/* Sanity check */
1109 	if ((attr == NULL) || (*attr == NULL) ||
1110 	    (dn == NULL) || (cred == NULL))
1111 		return (NS_LDAP_INVALID_PARAM);
1112 
1113 	mods = __s_api_makeModList(service, attr, LDAP_MOD_DELETE, flags);
1114 	if (mods == NULL) {
1115 		return (NS_LDAP_MEMORY);
1116 	}
1117 
1118 	rc = write_state_machine(LDAP_REQ_MODIFY,
1119 	    (char *)dn, mods, cred, flags, errorp);
1120 
1121 	freeModList(mods);
1122 	return (rc);
1123 }
1124 
1125 /*ARGSUSED*/
1126 int
1127 __ns_ldap_repAttr(
1128 	const char *service,
1129 	const char *dn,
1130 	const ns_ldap_attr_t * const *attr,
1131 	const ns_cred_t *cred,
1132 	const int flags,
1133 	ns_ldap_error_t ** errorp)
1134 {
1135 	LDAPMod		**mods;
1136 	int		rc = 0;
1137 
1138 #ifdef DEBUG
1139 	(void) fprintf(stderr, "__ns_ldap_repAttr START\n");
1140 #endif
1141 	*errorp = NULL;
1142 
1143 	/* Sanity check */
1144 	if ((attr == NULL) || (*attr == NULL) ||
1145 	    (dn == NULL) || (cred == NULL))
1146 		return (NS_LDAP_INVALID_PARAM);
1147 	mods = __s_api_makeModList(service, attr, LDAP_MOD_REPLACE, flags);
1148 	if (mods == NULL) {
1149 		return (NS_LDAP_MEMORY);
1150 	}
1151 
1152 	rc = write_state_machine(LDAP_REQ_MODIFY,
1153 	    (char *)dn, mods, cred, flags, errorp);
1154 
1155 	freeModList(mods);
1156 	return (rc);
1157 }
1158 
1159 
1160 /*ARGSUSED*/
1161 int
1162 __ns_ldap_addEntry(
1163 	const char *service,
1164 	const char *dn,
1165 	const ns_ldap_entry_t *entry,
1166 	const ns_cred_t *cred,
1167 	const int flags,
1168 	ns_ldap_error_t ** errorp)
1169 {
1170 	char		*new_dn = NULL;
1171 	LDAPMod		**mods = NULL;
1172 	const ns_ldap_attr_t	* const *attr;
1173 	int		nAttr = 0;
1174 	int		rc = 0;
1175 
1176 #ifdef DEBUG
1177 	(void) fprintf(stderr, "__ns_ldap_addEntry START\n");
1178 #endif
1179 
1180 	if ((entry == NULL) || (dn == NULL) || (cred == NULL))
1181 		return (NS_LDAP_INVALID_PARAM);
1182 	*errorp = NULL;
1183 
1184 	/* Construct array of LDAPMod representing attributes of new entry. */
1185 
1186 	nAttr = entry->attr_count;
1187 	attr = (const ns_ldap_attr_t * const *)(entry->attr_pair);
1188 	mods = __s_api_makeModListCount(service, attr, LDAP_MOD_ADD,
1189 	    nAttr, flags);
1190 	if (mods == NULL) {
1191 		return (NS_LDAP_MEMORY);
1192 	}
1193 
1194 	rc = replace_mapped_attr_in_dn(service, dn, &new_dn);
1195 	if (rc != NS_LDAP_SUCCESS) {
1196 		freeModList(mods);
1197 		return (rc);
1198 	}
1199 
1200 	rc = write_state_machine(LDAP_REQ_ADD,
1201 	    new_dn ? new_dn : (char *)dn, mods, cred, flags, errorp);
1202 
1203 	if (new_dn)
1204 		free(new_dn);
1205 	freeModList(mods);
1206 	return (rc);
1207 }
1208 
1209 
1210 /*ARGSUSED*/
1211 int
1212 __ns_ldap_delEntry(
1213 	const char *service,
1214 	const char *dn,
1215 	const ns_cred_t *cred,
1216 	const int flags,
1217 	ns_ldap_error_t ** errorp)
1218 {
1219 	int		rc;
1220 
1221 #ifdef DEBUG
1222 	(void) fprintf(stderr, "__ns_ldap_delEntry START\n");
1223 #endif
1224 	if ((dn == NULL) || (cred == NULL))
1225 		return (NS_LDAP_INVALID_PARAM);
1226 
1227 	*errorp = NULL;
1228 
1229 	rc = write_state_machine(LDAP_REQ_DELETE,
1230 	    (char *)dn, NULL, cred, flags, errorp);
1231 
1232 	return (rc);
1233 }
1234 
1235 /*
1236  * Add Typed Entry Helper routines
1237  */
1238 
1239 /*
1240  * Add Typed Entry Conversion routines
1241  */
1242 
1243 static int
1244 __s_add_attr(ns_ldap_entry_t *e, char *attrname, char *value)
1245 {
1246 	ns_ldap_attr_t	*a;
1247 	char		*v;
1248 
1249 	a = (ns_ldap_attr_t *)calloc(1, sizeof (ns_ldap_attr_t));
1250 	if (a == NULL)
1251 		return (NS_LDAP_MEMORY);
1252 	a->attrname = strdup(attrname);
1253 	if (a->attrname == NULL)
1254 		return (NS_LDAP_MEMORY);
1255 	a->attrvalue = (char **)calloc(1, sizeof (char **));
1256 	if (a->attrvalue == NULL)
1257 		return (NS_LDAP_MEMORY);
1258 	a->value_count = 1;
1259 	a->attrvalue[0] = NULL;
1260 	v = strdup(value);
1261 	if (v == NULL)
1262 		return (NS_LDAP_MEMORY);
1263 	a->attrvalue[0] = v;
1264 	e->attr_pair[e->attr_count] = a;
1265 	e->attr_count++;
1266 	return (NS_LDAP_SUCCESS);
1267 }
1268 
1269 static int
1270 __s_add_attrlist(ns_ldap_entry_t *e, char *attrname, char **argv)
1271 {
1272 	ns_ldap_attr_t	*a;
1273 	char		*v;
1274 	char		**av;
1275 	int		i, j;
1276 
1277 	a = (ns_ldap_attr_t *)calloc(1, sizeof (ns_ldap_attr_t));
1278 	if (a == NULL)
1279 		return (NS_LDAP_MEMORY);
1280 	a->attrname = strdup(attrname);
1281 	if (a->attrname == NULL)
1282 		return (NS_LDAP_MEMORY);
1283 
1284 	for (i = 0, av = argv; *av != NULL; av++, i++)
1285 		;
1286 
1287 	a->attrvalue = (char **)calloc(i, sizeof (char *));
1288 
1289 	if (a->attrvalue == NULL)
1290 		return (NS_LDAP_MEMORY);
1291 
1292 	a->value_count = i;
1293 	for (j = 0; j < i; j++) {
1294 		v = strdup(argv[j]);
1295 		if (v == NULL)
1296 			return (NS_LDAP_MEMORY);
1297 		a->attrvalue[j] = v;
1298 	}
1299 	e->attr_pair[e->attr_count] = a;
1300 	e->attr_count++;
1301 	return (NS_LDAP_SUCCESS);
1302 }
1303 
1304 static ns_ldap_entry_t *
1305 __s_mk_entry(char **objclass, int max_attr)
1306 {
1307 	ns_ldap_entry_t *e;
1308 	e = (ns_ldap_entry_t *)calloc(1, sizeof (ns_ldap_entry_t));
1309 	if (e == NULL)
1310 		return (NULL);
1311 	/* allocate attributes, +1 for objectclass, +1 for NULL terminator */
1312 	e->attr_pair = (ns_ldap_attr_t **)
1313 	    calloc(max_attr + 2, sizeof (ns_ldap_attr_t *));
1314 	if (e->attr_pair == NULL) {
1315 		free(e);
1316 		return (NULL);
1317 	}
1318 	e->attr_count = 0;
1319 	if (__s_add_attrlist(e, "objectClass", objclass) != NS_LDAP_SUCCESS) {
1320 		free(e->attr_pair);
1321 		free(e);
1322 		return (NULL);
1323 	}
1324 	return (e);
1325 }
1326 
1327 
1328 /*
1329  * Conversion:			passwd
1330  * Input format:		struct passwd
1331  * Exported objectclass:	posixAccount
1332  */
1333 static int
1334 __s_cvt_passwd(const void *data, char **rdn,
1335 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
1336 {
1337 	ns_ldap_entry_t	*e;
1338 	int		rc;
1339 	char		trdn[RDNSIZE];
1340 	/* routine specific */
1341 	struct passwd	*ptr;
1342 	int		max_attr = 9;
1343 	char		ibuf[10];
1344 	static		char *oclist[] = {
1345 			"posixAccount",
1346 			"shadowAccount",
1347 			"account",
1348 			"top",
1349 			NULL
1350 			};
1351 
1352 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
1353 		return (NS_LDAP_OP_FAILED);
1354 	*entry = e = __s_mk_entry(oclist, max_attr);
1355 	if (e == NULL)
1356 		return (NS_LDAP_MEMORY);
1357 
1358 	/* Convert the structure */
1359 	ptr = (struct passwd *)data;
1360 
1361 	if (ptr->pw_name == NULL || ptr->pw_uid < 0 ||
1362 	    ptr->pw_gid < 0 || ptr->pw_dir == NULL) {
1363 		__ns_ldap_freeEntry(e);
1364 		*entry = NULL;
1365 		return (NS_LDAP_INVALID_PARAM);
1366 	}
1367 
1368 	/* Create an appropriate rdn */
1369 	(void) snprintf(trdn, RDNSIZE, "uid=%s", ptr->pw_name);
1370 	*rdn = strdup(trdn);
1371 	if (*rdn == NULL) {
1372 		__ns_ldap_freeEntry(e);
1373 		*entry = NULL;
1374 		return (NS_LDAP_MEMORY);
1375 	}
1376 
1377 	/* Error check the data and add the attributes */
1378 	rc = __s_add_attr(e, "uid", ptr->pw_name);
1379 	if (rc != NS_LDAP_SUCCESS) {
1380 		__s_cvt_freeEntryRdn(entry, rdn);
1381 		return (rc);
1382 	}
1383 	rc = __s_add_attr(e, "cn", ptr->pw_name);
1384 	if (rc != NS_LDAP_SUCCESS) {
1385 		__s_cvt_freeEntryRdn(entry, rdn);
1386 		return (rc);
1387 	}
1388 
1389 	if (ptr->pw_passwd != NULL &&
1390 		ptr->pw_passwd[0] != '\0') {
1391 		rc = __s_add_attr(e, "userPassword", ptr->pw_passwd);
1392 		if (rc != NS_LDAP_SUCCESS) {
1393 			__s_cvt_freeEntryRdn(entry, rdn);
1394 			return (rc);
1395 		}
1396 	}
1397 
1398 #ifdef _LP64
1399 	(void) sprintf(ibuf, "%d", ptr->pw_uid);
1400 #else
1401 	(void) sprintf(ibuf, "%ld", ptr->pw_uid);
1402 #endif
1403 	rc = __s_add_attr(e, "uidNumber", ibuf);
1404 	if (rc != NS_LDAP_SUCCESS) {
1405 		__s_cvt_freeEntryRdn(entry, rdn);
1406 		return (rc);
1407 	}
1408 
1409 #ifdef _LP64
1410 	(void) sprintf(ibuf, "%d", ptr->pw_gid);
1411 #else
1412 	(void) sprintf(ibuf, "%ld", ptr->pw_gid);
1413 #endif
1414 	rc = __s_add_attr(e, "gidNumber", ibuf);
1415 	if (rc != NS_LDAP_SUCCESS) {
1416 		__s_cvt_freeEntryRdn(entry, rdn);
1417 		return (rc);
1418 	}
1419 	if (ptr->pw_gecos != NULL &&
1420 		ptr->pw_gecos[0] != '\0') {
1421 		rc = __s_add_attr(e, "gecos", ptr->pw_gecos);
1422 		if (rc != NS_LDAP_SUCCESS) {
1423 			__s_cvt_freeEntryRdn(entry, rdn);
1424 			return (rc);
1425 		}
1426 	}
1427 
1428 	rc = __s_add_attr(e, "homeDirectory", ptr->pw_dir);
1429 	if (rc != NS_LDAP_SUCCESS) {
1430 		__s_cvt_freeEntryRdn(entry, rdn);
1431 		return (rc);
1432 	}
1433 	if (ptr->pw_shell != NULL &&
1434 		ptr->pw_shell[0] != '\0') {
1435 		rc = __s_add_attr(e, "loginShell", ptr->pw_shell);
1436 		if (rc != NS_LDAP_SUCCESS) {
1437 			__s_cvt_freeEntryRdn(entry, rdn);
1438 			return (rc);
1439 		}
1440 	}
1441 
1442 	return (NS_LDAP_SUCCESS);
1443 }
1444 
1445 /*
1446  * Conversion:			shadow
1447  * Input format:		struct shadow
1448  * Exported objectclass:	shadowAccount
1449  */
1450 static int
1451 __s_cvt_shadow(const void *data, char **rdn,
1452 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
1453 {
1454 	ns_ldap_entry_t	*e;
1455 	int		rc;
1456 	char		trdn[RDNSIZE];
1457 	/* routine specific */
1458 	struct spwd	*ptr;
1459 	int		max_attr = 10;
1460 	char		ibuf[10];
1461 	static		char *oclist[] = {
1462 			"posixAccount",
1463 			"shadowAccount",
1464 			"account",
1465 			"top",
1466 			NULL
1467 			};
1468 
1469 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
1470 		return (NS_LDAP_OP_FAILED);
1471 	*entry = e = __s_mk_entry(oclist, max_attr);
1472 	if (e == NULL)
1473 		return (NS_LDAP_MEMORY);
1474 
1475 	/* Convert the structure */
1476 	ptr = (struct spwd *)data;
1477 
1478 	if (ptr->sp_namp == NULL) {
1479 		__ns_ldap_freeEntry(e);
1480 		*entry = NULL;
1481 		return (NS_LDAP_INVALID_PARAM);
1482 	}
1483 
1484 	/* Create an appropriate rdn */
1485 	(void) snprintf(trdn, RDNSIZE, "uid=%s", ptr->sp_namp);
1486 	*rdn = strdup(trdn);
1487 	if (*rdn == NULL) {
1488 		__ns_ldap_freeEntry(e);
1489 		*entry = NULL;
1490 		return (NS_LDAP_MEMORY);
1491 	}
1492 
1493 	/* Error check the data and add the attributes */
1494 	rc = __s_add_attr(e, "uid", ptr->sp_namp);
1495 	if (rc != NS_LDAP_SUCCESS) {
1496 		__s_cvt_freeEntryRdn(entry, rdn);
1497 		return (rc);
1498 	}
1499 
1500 	if (ptr->sp_pwdp == NULL) {
1501 		__s_cvt_freeEntryRdn(entry, rdn);
1502 		return (NS_LDAP_INVALID_PARAM);
1503 	} else {
1504 		rc = __s_add_attr(e, "userPassword", ptr->sp_pwdp);
1505 		if (rc != NS_LDAP_SUCCESS) {
1506 			__s_cvt_freeEntryRdn(entry, rdn);
1507 			return (rc);
1508 		}
1509 	}
1510 	if (ptr->sp_lstchg >= 0) {
1511 		(void) sprintf(ibuf, "%d", ptr->sp_lstchg);
1512 		rc = __s_add_attr(e, "shadowLastChange", ibuf);
1513 		if (rc != NS_LDAP_SUCCESS) {
1514 			__s_cvt_freeEntryRdn(entry, rdn);
1515 			return (rc);
1516 		}
1517 	}
1518 	if (ptr->sp_min >= 0) {
1519 		(void) sprintf(ibuf, "%d", ptr->sp_min);
1520 		rc = __s_add_attr(e, "shadowMin", ibuf);
1521 		if (rc != NS_LDAP_SUCCESS) {
1522 			__s_cvt_freeEntryRdn(entry, rdn);
1523 			return (rc);
1524 		}
1525 	}
1526 	if (ptr->sp_max >= 0) {
1527 		(void) sprintf(ibuf, "%d", ptr->sp_max);
1528 		rc = __s_add_attr(e, "shadowMax", ibuf);
1529 		if (rc != NS_LDAP_SUCCESS) {
1530 			__s_cvt_freeEntryRdn(entry, rdn);
1531 			return (rc);
1532 		}
1533 	}
1534 	if (ptr->sp_warn >= 0) {
1535 		(void) sprintf(ibuf, "%d", ptr->sp_warn);
1536 		rc = __s_add_attr(e, "shadowWarning", ibuf);
1537 		if (rc != NS_LDAP_SUCCESS) {
1538 			__s_cvt_freeEntryRdn(entry, rdn);
1539 			return (rc);
1540 		}
1541 	}
1542 	if (ptr->sp_inact >= 0) {
1543 		(void) sprintf(ibuf, "%d", ptr->sp_inact);
1544 		rc = __s_add_attr(e, "shadowInactive", ibuf);
1545 		if (rc != NS_LDAP_SUCCESS) {
1546 			__s_cvt_freeEntryRdn(entry, rdn);
1547 			return (rc);
1548 		}
1549 	}
1550 	if (ptr->sp_expire >= 0) {
1551 		(void) sprintf(ibuf, "%d", ptr->sp_expire);
1552 		rc = __s_add_attr(e, "shadowExpire", ibuf);
1553 		if (rc != NS_LDAP_SUCCESS) {
1554 			__s_cvt_freeEntryRdn(entry, rdn);
1555 			return (rc);
1556 		}
1557 	}
1558 	(void) sprintf(ibuf, "%d", ptr->sp_flag);
1559 	rc = __s_add_attr(e, "shadowFlag", ibuf);
1560 	if (rc != NS_LDAP_SUCCESS) {
1561 		__s_cvt_freeEntryRdn(entry, rdn);
1562 		return (rc);
1563 	}
1564 
1565 	return (NS_LDAP_SUCCESS);
1566 }
1567 
1568 
1569 /*
1570  * Conversion:			group
1571  * Input format:		struct group
1572  * Exported objectclass:	posixGroup
1573  */
1574 static int
1575 __s_cvt_group(const void *data, char **rdn,
1576 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
1577 {
1578 	ns_ldap_entry_t	*e;
1579 	int		rc;
1580 	char		trdn[RDNSIZE];
1581 	/* routine specific */
1582 	struct group	*ptr;
1583 	int		i, j, k;
1584 	char		**nm, **lm;
1585 	int		max_attr = 4;
1586 	char		ibuf[10];
1587 	static		char *oclist[] = {
1588 			"posixGroup",
1589 			"top",
1590 			NULL
1591 			};
1592 
1593 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
1594 		return (NS_LDAP_OP_FAILED);
1595 	*entry = e = __s_mk_entry(oclist, max_attr);
1596 	if (e == NULL)
1597 		return (NS_LDAP_MEMORY);
1598 
1599 	/* Convert the structure */
1600 	ptr = (struct group *)data;
1601 
1602 	if (ptr->gr_name == NULL || ptr->gr_gid < 0) {
1603 		__ns_ldap_freeEntry(e);
1604 		*entry = NULL;
1605 		return (NS_LDAP_INVALID_PARAM);
1606 	}
1607 
1608 	/* Create an appropriate rdn */
1609 	(void) snprintf(trdn, RDNSIZE, "cn=%s", ptr->gr_name);
1610 	*rdn = strdup(trdn);
1611 	if (*rdn == NULL) {
1612 		__ns_ldap_freeEntry(e);
1613 		*entry = NULL;
1614 		return (NS_LDAP_MEMORY);
1615 	}
1616 
1617 	/* Error check the data and add the attributes */
1618 	rc = __s_add_attr(e, "cn", ptr->gr_name);
1619 	if (rc != NS_LDAP_SUCCESS) {
1620 		__s_cvt_freeEntryRdn(entry, rdn);
1621 		return (rc);
1622 	}
1623 
1624 #ifdef _LP64
1625 	(void) sprintf(ibuf, "%d", ptr->gr_gid);
1626 #else
1627 	(void) sprintf(ibuf, "%ld", ptr->gr_gid);
1628 #endif
1629 	rc = __s_add_attr(e, "gidNumber", ibuf);
1630 	if (rc != NS_LDAP_SUCCESS) {
1631 		__s_cvt_freeEntryRdn(entry, rdn);
1632 		return (rc);
1633 	}
1634 	if (ptr->gr_passwd && ptr->gr_passwd[0] != '\0') {
1635 		rc = __s_add_attr(e, "userPassword", ptr->gr_passwd);
1636 		if (rc != NS_LDAP_SUCCESS) {
1637 			__s_cvt_freeEntryRdn(entry, rdn);
1638 			return (rc);
1639 		}
1640 	}
1641 
1642 	if (ptr->gr_mem && ptr->gr_mem[0]) {
1643 		lm = ptr->gr_mem;
1644 		for (i = 0; *lm; i++, lm++)
1645 			;
1646 		lm = ptr->gr_mem;
1647 		nm = (char **)calloc(i+2, sizeof (char *));
1648 		if (nm == NULL) {
1649 			__s_cvt_freeEntryRdn(entry, rdn);
1650 			return (NS_LDAP_MEMORY);
1651 		}
1652 		for (j = 0; j < i; j++) {
1653 			nm[j] = strdup(lm[j]);
1654 			if (nm[j] == NULL) {
1655 				for (k = 0; k < j; k++)
1656 					free(nm[k]);
1657 				free(nm);
1658 				__s_cvt_freeEntryRdn(entry, rdn);
1659 				return (NS_LDAP_MEMORY);
1660 			}
1661 		}
1662 		rc = __s_add_attrlist(e, "memberUid", nm);
1663 		for (j = 0; j < i; j++) {
1664 			free(nm[j]);
1665 		}
1666 		free(nm);
1667 		nm = NULL;
1668 		if (rc != NS_LDAP_SUCCESS) {
1669 			__s_cvt_freeEntryRdn(entry, rdn);
1670 			return (rc);
1671 		}
1672 	}
1673 
1674 	return (NS_LDAP_SUCCESS);
1675 }
1676 
1677 /*
1678  * Conversion:			hosts
1679  * Input format:		struct hostent
1680  * Exported objectclass:	ipHost
1681  */
1682 static int
1683 __s_cvt_hosts(const void *data, char **rdn,
1684 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
1685 {
1686 	ns_ldap_entry_t	*e;
1687 	int		rc;
1688 	char		trdn[RDNSIZE];
1689 	/* routine specific */
1690 	struct hostent	*ptr;
1691 	int		max_attr = 6;
1692 	int		i, j, k;
1693 	char		**nm, **lm;
1694 	static		char *oclist[] = {
1695 			"ipHost",
1696 			"device",
1697 			"top",
1698 			NULL
1699 			};
1700 
1701 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
1702 		return (NS_LDAP_OP_FAILED);
1703 	*entry = e = __s_mk_entry(oclist, max_attr);
1704 	if (e == NULL)
1705 		return (NS_LDAP_MEMORY);
1706 
1707 	/* Convert the structure */
1708 	ptr = (struct hostent *)data;
1709 
1710 	if (ptr->h_name == NULL ||
1711 	    ptr->h_addr_list == NULL || ptr->h_addr_list[0] == '\0') {
1712 		__ns_ldap_freeEntry(e);
1713 		*entry = NULL;
1714 		return (NS_LDAP_INVALID_PARAM);
1715 	}
1716 
1717 	/* Create an appropriate rdn */
1718 	(void) snprintf(trdn, RDNSIZE, "cn=%s+ipHostNumber=%s",
1719 	    ptr->h_name, ptr->h_addr_list[0]);
1720 	*rdn = strdup(trdn);
1721 	if (*rdn == NULL) {
1722 		__ns_ldap_freeEntry(e);
1723 		*entry = NULL;
1724 		return (NS_LDAP_MEMORY);
1725 	}
1726 
1727 	/* Error check the data and add the attributes */
1728 	if (ptr->h_aliases && ptr->h_aliases[0]) {
1729 		lm = ptr->h_aliases;
1730 		for (i = 0; *lm; i++, lm++)
1731 			;
1732 		lm = ptr->h_aliases;
1733 		nm = (char **)calloc(i+2, sizeof (char *));
1734 		if (nm == NULL) {
1735 			__s_cvt_freeEntryRdn(entry, rdn);
1736 			return (NS_LDAP_MEMORY);
1737 		}
1738 		nm[0] = ptr->h_name;
1739 		for (j = 0; j < i; j++)
1740 			nm[j+1] = ptr->h_aliases[j];
1741 
1742 		rc = __s_add_attrlist(e, "cn", nm);
1743 		free(nm);
1744 		nm = NULL;
1745 		if (rc != NS_LDAP_SUCCESS) {
1746 			__s_cvt_freeEntryRdn(entry, rdn);
1747 			return (rc);
1748 		}
1749 	} else {
1750 		rc = __s_add_attr(e, "cn", ptr->h_name);
1751 		if (rc != NS_LDAP_SUCCESS) {
1752 			__s_cvt_freeEntryRdn(entry, rdn);
1753 			return (rc);
1754 		}
1755 	}
1756 
1757 	if (ptr->h_addr_list && ptr->h_addr_list[0]) {
1758 		lm = ptr->h_addr_list;
1759 		for (i = 0; *lm; i++, lm++)
1760 			;
1761 		lm = ptr->h_addr_list;
1762 		nm = (char **)calloc(i+2, sizeof (char *));
1763 		if (nm == NULL) {
1764 			__s_cvt_freeEntryRdn(entry, rdn);
1765 			return (NS_LDAP_MEMORY);
1766 		}
1767 		for (j = 0; j < i; j++) {
1768 			nm[j] = strdup(lm[j]);
1769 			if (nm[j] == NULL) {
1770 				for (k = 0; k < j; k++)
1771 					free(nm[k]);
1772 				free(nm);
1773 				__s_cvt_freeEntryRdn(entry, rdn);
1774 				return (NS_LDAP_MEMORY);
1775 			}
1776 		}
1777 		rc = __s_add_attrlist(e, "ipHostNumber", nm);
1778 		for (j = 0; j < i; j++) {
1779 			free(nm[j]);
1780 		}
1781 		free(nm);
1782 		nm = NULL;
1783 		if (rc != NS_LDAP_SUCCESS) {
1784 			__s_cvt_freeEntryRdn(entry, rdn);
1785 			return (rc);
1786 		}
1787 	} else {
1788 		__s_cvt_freeEntryRdn(entry, rdn);
1789 		return (NS_LDAP_INVALID_PARAM);
1790 	}
1791 
1792 	return (NS_LDAP_SUCCESS);
1793 }
1794 
1795 /*
1796  * Conversion:			rpc
1797  * Input format:		struct rpcent
1798  * Exported objectclass:	oncRpc
1799  */
1800 static int
1801 __s_cvt_rpc(const void *data, char **rdn,
1802 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
1803 {
1804 	ns_ldap_entry_t	*e;
1805 	int		rc;
1806 	char		trdn[RDNSIZE];
1807 	/* routine specific */
1808 	struct rpcent	*ptr;
1809 	int		max_attr = 3;
1810 	int		i, j;
1811 	char		**nm;
1812 	char		ibuf[10];
1813 	static		char *oclist[] = {
1814 			"oncRpc",
1815 			"top",
1816 			NULL
1817 			};
1818 
1819 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
1820 		return (NS_LDAP_OP_FAILED);
1821 	*entry = e = __s_mk_entry(oclist, max_attr);
1822 	if (e == NULL)
1823 		return (NS_LDAP_MEMORY);
1824 
1825 	/* Convert the structure */
1826 	ptr = (struct rpcent *)data;
1827 
1828 	if (ptr->r_name == NULL || ptr->r_number < 0) {
1829 		__ns_ldap_freeEntry(e);
1830 		*entry = NULL;
1831 		return (NS_LDAP_INVALID_PARAM);
1832 	}
1833 
1834 	/* Create an appropriate rdn */
1835 	(void) snprintf(trdn, RDNSIZE, "cn=%s", ptr->r_name);
1836 	*rdn = strdup(trdn);
1837 	if (*rdn == NULL) {
1838 		__ns_ldap_freeEntry(e);
1839 		*entry = NULL;
1840 		return (NS_LDAP_MEMORY);
1841 	}
1842 
1843 	/* Error check the data and add the attributes */
1844 	if (ptr->r_aliases && ptr->r_aliases[0]) {
1845 		nm = ptr->r_aliases;
1846 		for (i = 0; *nm; i++, nm++)
1847 			;
1848 		nm = (char **)calloc(i+2, sizeof (char *));
1849 		if (nm == NULL) {
1850 			__s_cvt_freeEntryRdn(entry, rdn);
1851 			return (NS_LDAP_MEMORY);
1852 		}
1853 		nm[0] = ptr->r_name;
1854 		for (j = 0; j < i; j++)
1855 			nm[j+1] = ptr->r_aliases[j];
1856 
1857 		rc = __s_add_attrlist(e, "cn", nm);
1858 		free(nm);
1859 		nm = NULL;
1860 		if (rc != NS_LDAP_SUCCESS) {
1861 			__s_cvt_freeEntryRdn(entry, rdn);
1862 			return (rc);
1863 		}
1864 	} else {
1865 		rc = __s_add_attr(e, "cn", ptr->r_name);
1866 		if (rc != NS_LDAP_SUCCESS) {
1867 			__s_cvt_freeEntryRdn(entry, rdn);
1868 			return (rc);
1869 		}
1870 	}
1871 
1872 	if (ptr->r_number >= 0) {
1873 		(void) sprintf(ibuf, "%d", ptr->r_number);
1874 		rc = __s_add_attr(e, "oncRpcNumber", ibuf);
1875 		if (rc != NS_LDAP_SUCCESS) {
1876 			__s_cvt_freeEntryRdn(entry, rdn);
1877 			return (rc);
1878 		}
1879 	}
1880 
1881 	return (NS_LDAP_SUCCESS);
1882 
1883 }
1884 
1885 /*
1886  * Conversion:			protocols
1887  * Input format:		struct protoent
1888  * Exported objectclass:	ipProtocol
1889  */
1890 static int
1891 __s_cvt_protocols(const void *data, char **rdn,
1892 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
1893 {
1894 	ns_ldap_entry_t	*e;
1895 	int		rc;
1896 	char		trdn[RDNSIZE];
1897 	/* routine specific */
1898 	struct protoent	*ptr;
1899 	int		max_attr = 3;
1900 	int		i, j;
1901 	char		ibuf[10];
1902 	char		**nm;
1903 	static		char *oclist[] = {
1904 			"ipProtocol",
1905 			"top",
1906 			NULL
1907 			};
1908 
1909 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
1910 		return (NS_LDAP_OP_FAILED);
1911 	*entry = e = __s_mk_entry(oclist, max_attr);
1912 	if (e == NULL)
1913 		return (NS_LDAP_MEMORY);
1914 
1915 	/* Convert the structure */
1916 	ptr = (struct protoent *)data;
1917 
1918 	if (ptr->p_name == NULL || ptr->p_proto < 0) {
1919 		__ns_ldap_freeEntry(e);
1920 		*entry = NULL;
1921 		return (NS_LDAP_INVALID_PARAM);
1922 	}
1923 
1924 	/* Create an appropriate rdn */
1925 	(void) snprintf(trdn, RDNSIZE, "cn=%s", ptr->p_name);
1926 	*rdn = strdup(trdn);
1927 	if (*rdn == NULL) {
1928 		__ns_ldap_freeEntry(e);
1929 		*entry = NULL;
1930 		return (NS_LDAP_MEMORY);
1931 	}
1932 
1933 	/* Error check the data and add the attributes */
1934 	if (ptr->p_aliases && ptr->p_aliases[0]) {
1935 		nm = ptr->p_aliases;
1936 		for (i = 0; *nm; i++, nm++)
1937 			;
1938 		nm = (char **)calloc(i+2, sizeof (char *));
1939 		if (nm == NULL) {
1940 			__s_cvt_freeEntryRdn(entry, rdn);
1941 			return (NS_LDAP_MEMORY);
1942 		}
1943 		nm[0] = ptr->p_name;
1944 		for (j = 0; j < i; j++)
1945 			nm[j+1] = ptr->p_aliases[j];
1946 
1947 		rc = __s_add_attrlist(e, "cn", nm);
1948 		free(nm);
1949 		nm = NULL;
1950 		if (rc != NS_LDAP_SUCCESS) {
1951 			__s_cvt_freeEntryRdn(entry, rdn);
1952 			return (rc);
1953 		}
1954 	} else {
1955 		rc = __s_add_attr(e, "cn", ptr->p_name);
1956 		if (rc != NS_LDAP_SUCCESS) {
1957 			__s_cvt_freeEntryRdn(entry, rdn);
1958 			return (rc);
1959 		}
1960 	}
1961 
1962 	(void) sprintf(ibuf, "%d", ptr->p_proto);
1963 	rc = __s_add_attr(e, "ipProtocolNumber", ibuf);
1964 	if (rc != NS_LDAP_SUCCESS) {
1965 		__s_cvt_freeEntryRdn(entry, rdn);
1966 		return (rc);
1967 	}
1968 
1969 	return (NS_LDAP_SUCCESS);
1970 
1971 }
1972 
1973 /*
1974  * Conversion:			services
1975  * Input format:		struct servent
1976  * Exported objectclass:	ipService
1977  */
1978 static int
1979 __s_cvt_services(const void *data, char **rdn,
1980 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
1981 {
1982 	ns_ldap_entry_t	*e;
1983 	int		rc;
1984 	char		trdn[RDNSIZE];
1985 	/* routine specific */
1986 	struct servent	*ptr;
1987 	int		max_attr = 4;
1988 	int		i, j;
1989 	char		ibuf[10];
1990 	char		**nm;
1991 	static		char *oclist[] = {
1992 			"ipService",
1993 			"top",
1994 			NULL
1995 			};
1996 
1997 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
1998 		return (NS_LDAP_OP_FAILED);
1999 	*entry = e = __s_mk_entry(oclist, max_attr);
2000 	if (e == NULL)
2001 		return (NS_LDAP_MEMORY);
2002 
2003 	/* Convert the structure */
2004 	ptr = (struct servent *)data;
2005 
2006 	if (ptr->s_name == NULL || ptr->s_port < 0 || ptr->s_proto == '\0') {
2007 		__ns_ldap_freeEntry(e);
2008 		*entry = NULL;
2009 		return (NS_LDAP_INVALID_PARAM);
2010 	}
2011 
2012 	/* Create an appropriate rdn */
2013 	(void) snprintf(trdn, RDNSIZE, "cn=%s+ipServiceProtocol=%s",
2014 				ptr->s_name, ptr->s_proto);
2015 	*rdn = strdup(trdn);
2016 	if (*rdn == NULL) {
2017 		__ns_ldap_freeEntry(e);
2018 		*entry = NULL;
2019 		return (NS_LDAP_MEMORY);
2020 	}
2021 
2022 	/* Error check the data and add the attributes */
2023 	if (ptr->s_aliases && ptr->s_aliases[0]) {
2024 		nm = ptr->s_aliases;
2025 		for (i = 0; *nm; i++, nm++)
2026 			;
2027 		nm = (char **)calloc(i+2, sizeof (char *));
2028 		if (nm == NULL) {
2029 			__s_cvt_freeEntryRdn(entry, rdn);
2030 			return (NS_LDAP_MEMORY);
2031 		}
2032 		nm[0] = ptr->s_name;
2033 		for (j = 0; j < i; j++)
2034 			nm[j+1] = ptr->s_aliases[j];
2035 
2036 		rc = __s_add_attrlist(e, "cn", nm);
2037 		free(nm);
2038 		nm = NULL;
2039 		if (rc != NS_LDAP_SUCCESS) {
2040 			__s_cvt_freeEntryRdn(entry, rdn);
2041 			return (rc);
2042 		}
2043 	} else {
2044 		rc = __s_add_attr(e, "cn", ptr->s_name);
2045 		if (rc != NS_LDAP_SUCCESS) {
2046 			__s_cvt_freeEntryRdn(entry, rdn);
2047 			return (rc);
2048 		}
2049 	}
2050 
2051 	(void) sprintf(ibuf, "%d", ptr->s_port);
2052 	rc = __s_add_attr(e, "ipServicePort", ibuf);
2053 	if (rc != NS_LDAP_SUCCESS) {
2054 		__s_cvt_freeEntryRdn(entry, rdn);
2055 		return (rc);
2056 	}
2057 	rc = __s_add_attr(e, "ipServiceProtocol", ptr->s_proto);
2058 	if (rc != NS_LDAP_SUCCESS) {
2059 		__s_cvt_freeEntryRdn(entry, rdn);
2060 		return (rc);
2061 	}
2062 
2063 	return (NS_LDAP_SUCCESS);
2064 }
2065 
2066 /*
2067  * Conversion:			networks
2068  * Input format:		struct netent
2069  * Exported objectclass:	ipNetwork
2070  */
2071 static int
2072 __s_cvt_networks(const void *data, char **rdn,
2073 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
2074 {
2075 	ns_ldap_entry_t	*e;
2076 	int		rc;
2077 	char		trdn[RDNSIZE];
2078 	/* routine specific */
2079 	struct netent	*ptr;
2080 	int		max_attr = 4;
2081 	int		i, j;
2082 	char		cp[64];
2083 	char		**nm;
2084 	static		char *oclist[] = {
2085 			"ipNetwork",
2086 			"top",
2087 			NULL
2088 			};
2089 
2090 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
2091 		return (NS_LDAP_OP_FAILED);
2092 	*entry = e = __s_mk_entry(oclist, max_attr);
2093 	if (e == NULL)
2094 		return (NS_LDAP_MEMORY);
2095 
2096 	/* Convert the structure */
2097 	ptr = (struct netent *)data;
2098 
2099 	if (ptr->n_name == NULL || ptr->n_net == 0) {
2100 		__ns_ldap_freeEntry(e);
2101 		*entry = NULL;
2102 		return (NS_LDAP_INVALID_PARAM);
2103 	}
2104 
2105 	(void) snprintf(cp, sizeof (cp), "%d.%d.%d.%d",
2106 			(ptr->n_net & 0xFF000000) >> 24,
2107 			(ptr->n_net & 0x00FF0000) >> 16,
2108 			(ptr->n_net & 0x0000FF00) >> 8,
2109 			(ptr->n_net & 0x000000FF));
2110 
2111 	/* Create an appropriate rdn */
2112 	(void) snprintf(trdn, RDNSIZE, "ipNetworkNumber=%s", cp);
2113 	*rdn = strdup(trdn);
2114 	if (*rdn == NULL) {
2115 		__ns_ldap_freeEntry(e);
2116 		*entry = NULL;
2117 		return (NS_LDAP_MEMORY);
2118 	}
2119 
2120 	/* Error check the data and add the attributes */
2121 	if (ptr->n_aliases && ptr->n_aliases[0]) {
2122 		nm = ptr->n_aliases;
2123 		for (i = 0; *nm; i++, nm++)
2124 			;
2125 		nm = (char **)calloc(i+2, sizeof (char *));
2126 		if (nm == NULL) {
2127 			__s_cvt_freeEntryRdn(entry, rdn);
2128 			return (NS_LDAP_MEMORY);
2129 		}
2130 		nm[0] = ptr->n_name;
2131 		for (j = 0; j < i; j++)
2132 			nm[j+1] = ptr->n_aliases[j];
2133 
2134 		rc = __s_add_attrlist(e, "cn", nm);
2135 		free(nm);
2136 		nm = NULL;
2137 		if (rc != NS_LDAP_SUCCESS) {
2138 			__s_cvt_freeEntryRdn(entry, rdn);
2139 			return (rc);
2140 		}
2141 	} else {
2142 		rc = __s_add_attr(e, "cn", ptr->n_name);
2143 		if (rc != NS_LDAP_SUCCESS) {
2144 			__s_cvt_freeEntryRdn(entry, rdn);
2145 			return (rc);
2146 		}
2147 	}
2148 
2149 	rc = __s_add_attr(e, "ipNetworkNumber", cp);
2150 	if (rc != NS_LDAP_SUCCESS) {
2151 		__s_cvt_freeEntryRdn(entry, rdn);
2152 		return (rc);
2153 	}
2154 
2155 	return (NS_LDAP_SUCCESS);
2156 
2157 }
2158 /*
2159  * Conversion:			netmasks
2160  * Input format:		struct _ns_netmasks
2161  * Exported objectclass:	ipNetwork
2162  */
2163 static int
2164 __s_cvt_netmasks(const void *data, char **rdn,
2165 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
2166 {
2167 	ns_ldap_entry_t	*e;
2168 	int		rc;
2169 	char		trdn[RDNSIZE];
2170 	/* routine specific */
2171 	struct _ns_netmasks *ptr;
2172 	int		max_attr = 4;
2173 	static		char *oclist[] = {
2174 			"ipNetwork",
2175 			"top",
2176 			NULL
2177 			};
2178 
2179 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
2180 		return (NS_LDAP_OP_FAILED);
2181 	*entry = e = __s_mk_entry(oclist, max_attr);
2182 	if (e == NULL)
2183 		return (NS_LDAP_MEMORY);
2184 
2185 	/* Convert the structure */
2186 	ptr = (struct _ns_netmasks *)data;
2187 
2188 	if (ptr->netnumber == NULL) {
2189 		__ns_ldap_freeEntry(e);
2190 		*entry = NULL;
2191 		return (NS_LDAP_INVALID_PARAM);
2192 	}
2193 
2194 	/* Create an appropriate rdn */
2195 	(void) snprintf(trdn, RDNSIZE, "ipNetworkNumber=%s", ptr->netnumber);
2196 	*rdn = strdup(trdn);
2197 	if (*rdn == NULL) {
2198 		__ns_ldap_freeEntry(e);
2199 		*entry = NULL;
2200 		return (NS_LDAP_MEMORY);
2201 	}
2202 
2203 	/* Error check the data and add the attributes */
2204 		rc = __s_add_attr(e, "ipNetworkNumber", ptr->netnumber);
2205 		if (rc != NS_LDAP_SUCCESS) {
2206 			__s_cvt_freeEntryRdn(entry, rdn);
2207 			return (rc);
2208 		}
2209 
2210 	if (ptr->netmask != '\0') {
2211 		rc = __s_add_attr(e, "ipNetmaskNumber", ptr->netmask);
2212 		if (rc != NS_LDAP_SUCCESS) {
2213 			__s_cvt_freeEntryRdn(entry, rdn);
2214 			return (rc);
2215 		}
2216 	}
2217 
2218 	return (NS_LDAP_SUCCESS);
2219 
2220 }
2221 /*
2222  * Conversion:			netgroups
2223  * Input format:		struct _ns_netgroups
2224  * Exported objectclass:	nisNetgroup
2225  */
2226 static int
2227 __s_cvt_netgroups(const void *data, char **rdn,
2228 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
2229 {
2230 	ns_ldap_entry_t	*e;
2231 	int		rc;
2232 	char		trdn[RDNSIZE];
2233 	/* routine specific */
2234 	struct _ns_netgroups *ptr;
2235 	int		max_attr = 6;
2236 	int		i, j;
2237 	char		**nm;
2238 	static		char *oclist[] = {
2239 			"nisNetgroup",
2240 			"top",
2241 			NULL
2242 			};
2243 
2244 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
2245 		return (NS_LDAP_OP_FAILED);
2246 	*entry = e = __s_mk_entry(oclist, max_attr);
2247 	if (e == NULL)
2248 		return (NS_LDAP_MEMORY);
2249 
2250 	/* Convert the structure */
2251 	ptr = (struct _ns_netgroups *)data;
2252 
2253 	if (ptr->name == NULL) {
2254 		__ns_ldap_freeEntry(e);
2255 		*entry = NULL;
2256 		return (NS_LDAP_INVALID_PARAM);
2257 	}
2258 
2259 	/* Create an appropriate rdn */
2260 	(void) snprintf(trdn, RDNSIZE, "cn=%s", ptr->name);
2261 	*rdn = strdup(trdn);
2262 	if (*rdn == NULL) {
2263 		__ns_ldap_freeEntry(e);
2264 		*entry = NULL;
2265 		return (NS_LDAP_MEMORY);
2266 	}
2267 
2268 	if (ptr->name != '\0') {
2269 		rc = __s_add_attr(e, "cn", ptr->name);
2270 		if (rc != NS_LDAP_SUCCESS) {
2271 			__s_cvt_freeEntryRdn(entry, rdn);
2272 			return (rc);
2273 		}
2274 	}
2275 
2276 	/* Error check the data and add the attributes */
2277 	if (ptr->triplet && ptr->triplet[0]) {
2278 		nm = ptr->triplet;
2279 		for (i = 0; *nm; i++, nm++)
2280 			;
2281 		nm = (char **)calloc(i+2, sizeof (char *));
2282 		if (nm == NULL) {
2283 			__s_cvt_freeEntryRdn(entry, rdn);
2284 			return (NS_LDAP_MEMORY);
2285 		}
2286 		for (j = 0; j < i; j++)
2287 			nm[j] = ptr->triplet[j];
2288 
2289 		rc = __s_add_attrlist(e, "nisNetgroupTriple", nm);
2290 		free(nm);
2291 		nm = NULL;
2292 		if (rc != NS_LDAP_SUCCESS) {
2293 			__s_cvt_freeEntryRdn(entry, rdn);
2294 			return (rc);
2295 		}
2296 	}
2297 	if (ptr->netgroup && ptr->netgroup[0]) {
2298 		nm = ptr->netgroup;
2299 		for (i = 0; *nm; i++, nm++)
2300 			;
2301 		nm = (char **)calloc(i+2, sizeof (char *));
2302 		if (nm == NULL) {
2303 			__s_cvt_freeEntryRdn(entry, rdn);
2304 			return (NS_LDAP_MEMORY);
2305 		}
2306 		for (j = 0; j < i; j++)
2307 			nm[j] = ptr->netgroup[j];
2308 
2309 		rc = __s_add_attrlist(e, "memberNisNetgroup", nm);
2310 		free(nm);
2311 		nm = NULL;
2312 		if (rc != NS_LDAP_SUCCESS) {
2313 			__s_cvt_freeEntryRdn(entry, rdn);
2314 			return (rc);
2315 		}
2316 	}
2317 	return (NS_LDAP_SUCCESS);
2318 }
2319 /*
2320  * Conversion:			bootparams
2321  * Input format:		struct _ns_bootp
2322  * Exported objectclass:	bootableDevice, device
2323  */
2324 static int
2325 __s_cvt_bootparams(const void *data, char **rdn,
2326 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
2327 {
2328 	ns_ldap_entry_t	*e;
2329 	int		rc;
2330 	char		trdn[RDNSIZE];
2331 	/* routine specific */
2332 	struct _ns_bootp *ptr;
2333 	int		max_attr = 4;
2334 	int		i, j;
2335 	char		**nm;
2336 	static		char *oclist[] = {
2337 			"bootableDevice",
2338 			"device",
2339 			"top",
2340 			NULL
2341 			};
2342 
2343 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
2344 		return (NS_LDAP_OP_FAILED);
2345 	*entry = e = __s_mk_entry(oclist, max_attr);
2346 	if (e == NULL)
2347 		return (NS_LDAP_MEMORY);
2348 
2349 	/* Convert the structure */
2350 	ptr = (struct _ns_bootp *)data;
2351 
2352 	if (ptr->name == NULL) {
2353 		__ns_ldap_freeEntry(e);
2354 		*entry = NULL;
2355 		return (NS_LDAP_INVALID_PARAM);
2356 	}
2357 
2358 	/* Create an appropriate rdn */
2359 	(void) snprintf(trdn, RDNSIZE, "cn=%s", ptr->name);
2360 	*rdn = strdup(trdn);
2361 	if (*rdn == NULL) {
2362 		__ns_ldap_freeEntry(e);
2363 		*entry = NULL;
2364 		return (NS_LDAP_MEMORY);
2365 	}
2366 
2367 	if (ptr->name != '\0') {
2368 		rc = __s_add_attr(e, "cn", ptr->name);
2369 		if (rc != NS_LDAP_SUCCESS) {
2370 			__s_cvt_freeEntryRdn(entry, rdn);
2371 			return (rc);
2372 		}
2373 	}
2374 
2375 	/* Error check the data and add the attributes */
2376 	if (ptr->param && ptr->param[0]) {
2377 		nm = ptr->param;
2378 		for (i = 0; *nm; i++, nm++)
2379 			;
2380 		nm = (char **)calloc(i+2, sizeof (char *));
2381 		if (nm == NULL) {
2382 			__s_cvt_freeEntryRdn(entry, rdn);
2383 			return (NS_LDAP_MEMORY);
2384 		}
2385 		for (j = 0; j < i; j++)
2386 			nm[j] = ptr->param[j];
2387 
2388 		rc = __s_add_attrlist(e, "bootParameter", nm);
2389 		free(nm);
2390 		nm = NULL;
2391 		if (rc != NS_LDAP_SUCCESS) {
2392 			__s_cvt_freeEntryRdn(entry, rdn);
2393 			return (rc);
2394 		}
2395 	}
2396 
2397 	return (NS_LDAP_SUCCESS);
2398 
2399 }
2400 /*
2401  * Conversion:			ethers
2402  * Input format:		struct _ns_ethers
2403  * Exported objectclass:	ieee802Device, device
2404  */
2405 static int
2406 __s_cvt_ethers(const void *data, char **rdn,
2407 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
2408 {
2409 	ns_ldap_entry_t	*e;
2410 	int		rc;
2411 	char		trdn[RDNSIZE];
2412 	/* routine specific */
2413 	struct _ns_ethers	*ptr;
2414 	int		max_attr = 4;
2415 	static		char *oclist[] = {
2416 			"ieee802Device",
2417 			"device",
2418 			"top",
2419 			NULL
2420 			};
2421 
2422 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
2423 		return (NS_LDAP_OP_FAILED);
2424 	*entry = e = __s_mk_entry(oclist, max_attr);
2425 	if (e == NULL)
2426 		return (NS_LDAP_MEMORY);
2427 
2428 	/* Convert the structure */
2429 	ptr = (struct _ns_ethers *)data;
2430 
2431 	if (ptr->name == NULL || ptr->ether == '\0') {
2432 		__ns_ldap_freeEntry(e);
2433 		*entry = NULL;
2434 		return (NS_LDAP_INVALID_PARAM);
2435 	}
2436 
2437 	/* Create an appropriate rdn */
2438 	(void) snprintf(trdn, RDNSIZE, "cn=%s", ptr->name);
2439 	*rdn = strdup(trdn);
2440 	if (*rdn == NULL) {
2441 		__ns_ldap_freeEntry(e);
2442 		*entry = NULL;
2443 		return (NS_LDAP_MEMORY);
2444 	}
2445 
2446 	/* Error check the data and add the attributes */
2447 	rc = __s_add_attr(e, "cn", ptr->name);
2448 	if (rc != NS_LDAP_SUCCESS) {
2449 		__s_cvt_freeEntryRdn(entry, rdn);
2450 		return (rc);
2451 	}
2452 
2453 	rc = __s_add_attr(e, "macAddress", ptr->ether);
2454 	if (rc != NS_LDAP_SUCCESS) {
2455 		__s_cvt_freeEntryRdn(entry, rdn);
2456 		return (rc);
2457 	}
2458 
2459 	return (NS_LDAP_SUCCESS);
2460 }
2461 /*
2462  * This function is used when processing an ethers (objectclass: ieee802Device)
2463  * or a bootparams (objectclass: bootableDevice) entry, and the entry is
2464  * already found in LDAP. Since both ethers and bootparams share the same
2465  * LDAP container, we want to check that the entry found in LDAP is:
2466  * - either the same entry (same cn, same objectclass): we don't do anything
2467  *   in this case
2468  * - or an entry which does not have the objectclass we are interesting in:
2469  *   in this case, we modify the existing entry by adding the relevant
2470  *   objectclass (ieee802Device or bootableDevice) and the relevant attribute(s)
2471  *   from the attribute list previously computing by the relevant conversion
2472  *   function.
2473  *   Note: from conversion functions __s_cvt_ethers() and  __s_cvt_bootparams()
2474  *   we know that there is only 1 more attribute today to add (macAddress
2475  *   or bootParameter)
2476  */
2477 #define	_MAX_ATTR_ETHBOOTP	2
2478 static int
2479 modify_ethers_bootp(
2480 	const char *service,
2481 	const char *rdn,
2482 	const char *fulldn,
2483 	const ns_ldap_attr_t * const *attrlist,
2484 	const ns_cred_t *cred,
2485 	const int flags,
2486 	ns_ldap_error_t	 **errorp)
2487 {
2488 	char	filter[BUFSIZ];
2489 	ns_ldap_result_t *resultp;
2490 	int rc = 0;
2491 	int i;
2492 	ns_ldap_attr_t *new_attrlist[_MAX_ATTR_ETHBOOTP+1];
2493 	ns_ldap_attr_t new_attrlist0;
2494 	char *new_attrvalue0[1];
2495 	const ns_ldap_attr_t	* const *aptr = attrlist;
2496 	ns_ldap_attr_t *aptr2;
2497 	ns_ldap_error_t	 *new_errorp = NULL;
2498 
2499 	if (rdn == NULL || fulldn == NULL || attrlist == NULL ||
2500 		errorp == NULL || service == NULL)
2501 		return (NS_LDAP_OP_FAILED);
2502 
2503 	bzero(&new_attrlist, sizeof (new_attrlist));
2504 	bzero(&new_attrlist0, sizeof (new_attrlist0));
2505 	new_attrlist[0] = &new_attrlist0;
2506 	new_attrlist[0]->attrvalue = new_attrvalue0;
2507 
2508 	new_attrlist[0]->attrname = "objectclass";
2509 	new_attrlist[0]->value_count = 1;
2510 	if (strcasecmp(service, "ethers") == NULL) {
2511 		(void) snprintf(&filter[0], sizeof (filter),
2512 			"(&(objectClass=ieee802Device)(%s))",
2513 			rdn);
2514 		new_attrlist[0]->attrvalue[0] = "ieee802Device";
2515 	} else {
2516 		(void) snprintf(&filter[0], sizeof (filter),
2517 			"(&(objectClass=bootableDevice)(%s))",
2518 			rdn);
2519 		new_attrlist[0]->attrvalue[0] = "bootableDevice";
2520 	}
2521 
2522 	rc =  __ns_ldap_list(service, filter, NULL, (const char **)NULL,
2523 		NULL, NS_LDAP_SCOPE_SUBTREE, &resultp, &new_errorp,
2524 		NULL, NULL);
2525 
2526 	switch (rc) {
2527 	case NS_LDAP_SUCCESS:
2528 		/*
2529 		 * entry already exists for this service
2530 		 * return NS_LDAP_INTERNAL and do not modify the incoming errorp
2531 		 */
2532 		rc = NS_LDAP_INTERNAL;
2533 		break;
2534 	case NS_LDAP_NOTFOUND:
2535 		/*
2536 		 * entry not found with the given objectclasss but entry exists
2537 		 * hence add the relevant attribute (macAddress or bootparams).
2538 		 */
2539 		i = 1;
2540 		while (*aptr && (i < _MAX_ATTR_ETHBOOTP)) {
2541 			/* aptr2 needed here to avoid lint warning */
2542 			aptr2 = (ns_ldap_attr_t *)*aptr++;
2543 			if ((strcasecmp(aptr2->attrname, "cn") != 0) &&
2544 				(strcasecmp(aptr2->attrname,
2545 					"objectclass") != 0)) {
2546 				    new_attrlist[i++] =	(ns_ldap_attr_t *)aptr2;
2547 			}
2548 		}
2549 
2550 		if (i != _MAX_ATTR_ETHBOOTP) {
2551 			/* we haven't found all expected attributes */
2552 			rc = NS_LDAP_OP_FAILED;
2553 			break;
2554 		}
2555 
2556 		aptr = (const ns_ldap_attr_t	* const *) new_attrlist;
2557 		/* clean errorp first */
2558 		(void) __ns_ldap_freeError(errorp);
2559 		rc =  __ns_ldap_addAttr(service, fulldn, aptr, cred, flags,
2560 			errorp);
2561 		break;
2562 	default:
2563 		/*
2564 		 * unexpected error happenned
2565 		 * returning relevant error
2566 		 */
2567 		(void) __ns_ldap_freeError(errorp);
2568 		*errorp = new_errorp;
2569 		break;
2570 	}
2571 
2572 	return (rc);
2573 }
2574 
2575 /*
2576  * Conversion:			publickey
2577  * Input format:		struct _ns_pubkey
2578  * Exported objectclass:	NisKeyObject
2579  */
2580 static int
2581 __s_cvt_publickey(const void *data, char **rdn,
2582 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
2583 {
2584 	ns_ldap_entry_t	*e;
2585 	int		rc;
2586 	char		trdn[RDNSIZE];
2587 	/* routine specific */
2588 	struct _ns_pubkey	*ptr;
2589 	int		max_attr = 3;
2590 	static		char *oclist[] = {
2591 			"NisKeyObject",
2592 			NULL
2593 			};
2594 
2595 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
2596 		return (NS_LDAP_OP_FAILED);
2597 	*entry = e = __s_mk_entry(oclist, max_attr);
2598 	if (e == NULL)
2599 		return (NS_LDAP_MEMORY);
2600 
2601 	/* Convert the structure */
2602 	ptr = (struct _ns_pubkey *)data;
2603 
2604 	if (ptr->name == NULL || ptr->pubkey == '\0' || ptr->privkey == '\0') {
2605 		__ns_ldap_freeEntry(e);
2606 		*entry = NULL;
2607 		return (NS_LDAP_INVALID_PARAM);
2608 	}
2609 
2610 	/* Create an appropriate rdn */
2611 	if (ptr->hostcred == NS_HOSTCRED_FALSE)
2612 		(void) snprintf(trdn, RDNSIZE, "uid=%s", ptr->name);
2613 	else
2614 		(void) snprintf(trdn, RDNSIZE, "cn=%s", ptr->name);
2615 	*rdn = strdup(trdn);
2616 	if (*rdn == NULL) {
2617 		__ns_ldap_freeEntry(e);
2618 		*entry = NULL;
2619 		return (NS_LDAP_MEMORY);
2620 	}
2621 
2622 	/* Error check the data and add the attributes */
2623 
2624 	rc = __s_add_attr(e, "nisPublickey", ptr->pubkey);
2625 	if (rc != NS_LDAP_SUCCESS) {
2626 		__s_cvt_freeEntryRdn(entry, rdn);
2627 		return (rc);
2628 	}
2629 
2630 	rc = __s_add_attr(e, "nisSecretkey", ptr->privkey);
2631 	if (rc != NS_LDAP_SUCCESS) {
2632 		__s_cvt_freeEntryRdn(entry, rdn);
2633 		return (rc);
2634 	}
2635 
2636 	return (NS_LDAP_SUCCESS);
2637 }
2638 /*
2639  * Conversion:			aliases
2640  * Input format:		struct _ns_alias
2641  * Exported objectclass:	mailGroup
2642  */
2643 static int
2644 __s_cvt_aliases(const void *data, char **rdn,
2645 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
2646 {
2647 	ns_ldap_entry_t	*e;
2648 	int		rc;
2649 	char		trdn[RDNSIZE];
2650 	/* routine specific */
2651 	struct _ns_alias *ptr;
2652 	int		max_attr = 4;
2653 	int		i, j;
2654 	char		**nm;
2655 	static		char *oclist[] = {
2656 			"mailGroup",
2657 			"top",
2658 			NULL
2659 			};
2660 
2661 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
2662 		return (NS_LDAP_OP_FAILED);
2663 	*entry = e = __s_mk_entry(oclist, max_attr);
2664 	if (e == NULL)
2665 		return (NS_LDAP_MEMORY);
2666 
2667 	/* Convert the structure */
2668 	ptr = (struct _ns_alias *)data;
2669 
2670 	if (ptr->alias == NULL) {
2671 		__ns_ldap_freeEntry(e);
2672 		*entry = NULL;
2673 		return (NS_LDAP_INVALID_PARAM);
2674 	}
2675 
2676 	/* Create an appropriate rdn */
2677 	(void) snprintf(trdn, RDNSIZE, "cn=%s", ptr->alias);
2678 	*rdn = strdup(trdn);
2679 	if (*rdn == NULL) {
2680 		__ns_ldap_freeEntry(e);
2681 		*entry = NULL;
2682 		return (NS_LDAP_MEMORY);
2683 	}
2684 
2685 	if (ptr->alias != '\0') {
2686 		rc = __s_add_attr(e, "mail", (char *)ptr->alias);
2687 		if (rc != NS_LDAP_SUCCESS) {
2688 			__s_cvt_freeEntryRdn(entry, rdn);
2689 			return (rc);
2690 		}
2691 	}
2692 
2693 	/* Error check the data and add the attributes */
2694 	if (ptr->member && ptr->member[0]) {
2695 		nm = ptr->member;
2696 		for (i = 0; *nm; i++, nm++)
2697 			;
2698 		nm = (char **)calloc(i+2, sizeof (char *));
2699 		if (nm == NULL) {
2700 			__s_cvt_freeEntryRdn(entry, rdn);
2701 			return (NS_LDAP_MEMORY);
2702 		}
2703 		for (j = 0; j < i; j++)
2704 			nm[j] = ptr->member[j];
2705 
2706 		rc = __s_add_attrlist(e, "mgrpRFC822MailMember", nm);
2707 		free(nm);
2708 		nm = NULL;
2709 		if (rc != NS_LDAP_SUCCESS) {
2710 			__s_cvt_freeEntryRdn(entry, rdn);
2711 			return (rc);
2712 		}
2713 	}
2714 
2715 	return (NS_LDAP_SUCCESS);
2716 
2717 }
2718 /*
2719  * Conversion:			automount
2720  * Input format:		struct _ns_automount
2721  * Exported objectclass:	automount
2722  */
2723 static int
2724 __s_cvt_auto_mount(const void *data, char **rdn,
2725 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
2726 {
2727 	ns_ldap_entry_t	*e;
2728 	int		rc;
2729 	char		trdn[RDNSIZE];
2730 	/* routine specific */
2731 	struct _ns_automount *ptr;
2732 	int		max_attr = 6;
2733 	void		**paramVal = NULL;
2734 	char		**mappedschema = NULL;
2735 	int		version1 = 0;
2736 	static		char *oclist[] = {
2737 			NULL,
2738 			"top",
2739 			NULL
2740 			};
2741 
2742 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
2743 		return (NS_LDAP_OP_FAILED);
2744 
2745 	/* determine profile version number */
2746 	rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P, &paramVal, errorp);
2747 	if (paramVal && *paramVal &&
2748 		strcasecmp(*paramVal, NS_LDAP_VERSION_1) == 0)
2749 		version1 = 1;
2750 	if (paramVal)
2751 		(void) __ns_ldap_freeParam(&paramVal);
2752 	if (rc && errorp)
2753 		(void) __ns_ldap_freeError(errorp);
2754 
2755 	/* use old schema for version 1 profiles */
2756 	if (version1)
2757 		oclist[0] = "nisObject";
2758 	else
2759 		oclist[0] = "automount";
2760 
2761 	*entry = e = __s_mk_entry(oclist, max_attr);
2762 	if (e == NULL)
2763 		return (NS_LDAP_MEMORY);
2764 
2765 	/* Convert the structure */
2766 	ptr = (struct _ns_automount *)data;
2767 
2768 	if (ptr->key == NULL || ptr->value == '\0' || ptr->mapname == '\0') {
2769 		__ns_ldap_freeEntry(e);
2770 		*entry = NULL;
2771 		return (NS_LDAP_INVALID_PARAM);
2772 	}
2773 
2774 	/* Create an appropriate rdn */
2775 	(void) snprintf(trdn, RDNSIZE, version1 ? "cn=%s" : "automountKey=%s",
2776 		ptr->key);
2777 	*rdn = strdup(trdn);
2778 	if (*rdn == NULL) {
2779 		__ns_ldap_freeEntry(e);
2780 		*entry = NULL;
2781 		return (NS_LDAP_MEMORY);
2782 	}
2783 
2784 	if (ptr->key != '\0') {
2785 		rc = __s_add_attr(e, version1 ? "cn" : "automountKey",
2786 		(char *)ptr->key);
2787 		if (rc != NS_LDAP_SUCCESS) {
2788 			__s_cvt_freeEntryRdn(entry, rdn);
2789 			return (rc);
2790 		}
2791 	}
2792 
2793 	rc = __s_add_attr(e, version1 ? "nisMapEntry" : "automountInformation",
2794 		(char *)ptr->value);
2795 	if (rc != NS_LDAP_SUCCESS) {
2796 		__s_cvt_freeEntryRdn(entry, rdn);
2797 		return (rc);
2798 	}
2799 
2800 	/*
2801 	 * even for version 2, if automount is mapped to nisObject we
2802 	 * still need 'nisMapName' attribute
2803 	 */
2804 	mappedschema = __ns_ldap_getMappedObjectClass("automount", "automount");
2805 	if (mappedschema && mappedschema[0] &&
2806 		strcasecmp(mappedschema[0], "nisObject") == 0)
2807 		version1 = 1;
2808 	if (mappedschema)
2809 		__s_api_free2dArray(mappedschema);
2810 
2811 	if (version1) {
2812 		rc = __s_add_attr(e, "nisMapName", (char *)ptr->mapname);
2813 		if (rc != NS_LDAP_SUCCESS) {
2814 			__s_cvt_freeEntryRdn(entry, rdn);
2815 			return (rc);
2816 		}
2817 	}
2818 
2819 	return (NS_LDAP_SUCCESS);
2820 }
2821 /*
2822  * Conversion:			auth_attr
2823  * Input format:		authstr_t
2824  * Exported objectclass:	SolarisAuthAttr
2825  */
2826 static int
2827 __s_cvt_authattr(const void *data, char **rdn,
2828 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
2829 {
2830 	ns_ldap_entry_t	*e;
2831 	int		rc;
2832 	char		trdn[RDNSIZE];
2833 	/* routine specific */
2834 	authstr_t	*ptr;
2835 	int		max_attr = 6;
2836 	static		char *oclist[] = {
2837 			"SolarisAuthAttr",
2838 			"top",
2839 			NULL
2840 			};
2841 
2842 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
2843 		return (NS_LDAP_OP_FAILED);
2844 
2845 	*entry = e = __s_mk_entry(oclist, max_attr);
2846 	if (e == NULL)
2847 		return (NS_LDAP_MEMORY);
2848 
2849 	/* Convert the structure */
2850 	ptr = (authstr_t *)data;
2851 
2852 	if (ptr->name == NULL || ptr->name[0] == '\0' || ptr->attr == NULL) {
2853 		__ns_ldap_freeEntry(e);
2854 		*entry = NULL;
2855 		return (NS_LDAP_INVALID_PARAM);
2856 	}
2857 
2858 	/* Create an appropriate rdn */
2859 	(void) snprintf(trdn, RDNSIZE, "cn=%s", ptr->name);
2860 	*rdn = strdup(trdn);
2861 	if (*rdn == NULL) {
2862 		__ns_ldap_freeEntry(e);
2863 		*entry = NULL;
2864 		return (NS_LDAP_MEMORY);
2865 	}
2866 
2867 	rc = __s_add_attr(e, "cn", ptr->name);
2868 	if (rc != NS_LDAP_SUCCESS) {
2869 		__s_cvt_freeEntryRdn(entry, rdn);
2870 		return (rc);
2871 	}
2872 
2873 	rc = __s_add_attr(e, "SolarisAttrKeyValue", ptr->attr);
2874 	if (rc != NS_LDAP_SUCCESS) {
2875 		__s_cvt_freeEntryRdn(entry, rdn);
2876 		return (rc);
2877 	}
2878 
2879 	if (ptr->res1 != NULL) {
2880 		rc = __s_add_attr(e, "SolarisAttrReserved1", ptr->res1);
2881 		if (rc != NS_LDAP_SUCCESS) {
2882 			__s_cvt_freeEntryRdn(entry, rdn);
2883 			return (rc);
2884 		}
2885 	}
2886 
2887 	if (ptr->res2 != NULL) {
2888 		rc = __s_add_attr(e, "SolarisAttrReserved2", ptr->res2);
2889 		if (rc != NS_LDAP_SUCCESS) {
2890 			__s_cvt_freeEntryRdn(entry, rdn);
2891 			return (rc);
2892 		}
2893 	}
2894 
2895 	if (ptr->short_desc != NULL) {
2896 		rc = __s_add_attr(e, "SolarisAttrShortDesc", ptr->short_desc);
2897 		if (rc != NS_LDAP_SUCCESS) {
2898 			__s_cvt_freeEntryRdn(entry, rdn);
2899 			return (rc);
2900 		}
2901 	}
2902 
2903 	if (ptr->long_desc != NULL) {
2904 		rc = __s_add_attr(e, "SolarisAttrLongDesc", ptr->long_desc);
2905 		if (rc != NS_LDAP_SUCCESS) {
2906 			__s_cvt_freeEntryRdn(entry, rdn);
2907 			return (rc);
2908 		}
2909 	}
2910 
2911 	return (NS_LDAP_SUCCESS);
2912 }
2913 /*
2914  * Conversion:			exec_attr
2915  * Input format:		execstr_t
2916  * Exported objectclass:	SolarisExecAttr
2917  */
2918 static int
2919 __s_cvt_execattr(const void *data, char **rdn,
2920 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
2921 {
2922 	ns_ldap_entry_t	*e;
2923 	int		rc;
2924 	char		trdn[RDNSIZE];
2925 	/* routine specific */
2926 	execstr_t	*ptr;
2927 	int		max_attr = 7;
2928 	static		char *oclist[] = {
2929 			"SolarisExecAttr",
2930 			"SolarisProfAttr",
2931 			"top",
2932 			NULL
2933 			};
2934 
2935 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
2936 		return (NS_LDAP_OP_FAILED);
2937 
2938 	*entry = e = __s_mk_entry(oclist, max_attr);
2939 	if (e == NULL)
2940 		return (NS_LDAP_MEMORY);
2941 
2942 	/* Convert the structure */
2943 	ptr = (execstr_t *)data;
2944 
2945 	if (ptr->name == NULL || ptr->name[0] == '\0' ||
2946 	    ptr->policy == NULL || ptr->policy[0] == '\0' ||
2947 	    ptr->type == NULL || ptr->type[0] == '\0' ||
2948 	    ptr->id == NULL || ptr->id[0] == '\0') {
2949 		__ns_ldap_freeEntry(e);
2950 		*entry = NULL;
2951 		return (NS_LDAP_INVALID_PARAM);
2952 	}
2953 
2954 	/* Create an appropriate rdn */
2955 	(void) snprintf(trdn, RDNSIZE, "cn=%s+SolarisKernelSecurityPolicy=%s"
2956 	    "+SolarisProfileType=%s+SolarisProfileId=%s",
2957 	    ptr->name, ptr->policy, ptr->type, ptr->id);
2958 	*rdn = strdup(trdn);
2959 	if (*rdn == NULL) {
2960 		__ns_ldap_freeEntry(e);
2961 		*entry = NULL;
2962 		return (NS_LDAP_MEMORY);
2963 	}
2964 
2965 	rc = __s_add_attr(e, "cn", ptr->name);
2966 	if (rc != NS_LDAP_SUCCESS) {
2967 		__s_cvt_freeEntryRdn(entry, rdn);
2968 		return (rc);
2969 	}
2970 
2971 	rc = __s_add_attr(e, "SolarisKernelSecurityPolicy", ptr->policy);
2972 	if (rc != NS_LDAP_SUCCESS) {
2973 		__s_cvt_freeEntryRdn(entry, rdn);
2974 		return (rc);
2975 	}
2976 
2977 	rc = __s_add_attr(e, "SolarisProfileType", ptr->type);
2978 	if (rc != NS_LDAP_SUCCESS) {
2979 		__s_cvt_freeEntryRdn(entry, rdn);
2980 		return (rc);
2981 	}
2982 
2983 	rc = __s_add_attr(e, "SolarisProfileId", ptr->id);
2984 	if (rc != NS_LDAP_SUCCESS) {
2985 		__s_cvt_freeEntryRdn(entry, rdn);
2986 		return (rc);
2987 	}
2988 
2989 	rc = __s_add_attr(e, "SolarisAttrKeyValue", ptr->attr);
2990 	if (rc != NS_LDAP_SUCCESS) {
2991 		__s_cvt_freeEntryRdn(entry, rdn);
2992 		return (rc);
2993 	}
2994 
2995 	if (ptr->res1 != NULL) {
2996 		rc = __s_add_attr(e, "SolarisAttrRes1", ptr->res1);
2997 		if (rc != NS_LDAP_SUCCESS) {
2998 			__s_cvt_freeEntryRdn(entry, rdn);
2999 			return (rc);
3000 		}
3001 	}
3002 
3003 	if (ptr->res2 != NULL) {
3004 		rc = __s_add_attr(e, "SolarisAttrRes2", ptr->res2);
3005 		if (rc != NS_LDAP_SUCCESS) {
3006 			__s_cvt_freeEntryRdn(entry, rdn);
3007 			return (rc);
3008 		}
3009 	}
3010 
3011 	return (NS_LDAP_SUCCESS);
3012 }
3013 /*
3014  * Conversion:			prof_attr
3015  * Input format:		profstr_t
3016  * Exported objectclass:	SolarisProfAttr
3017  */
3018 static int
3019 __s_cvt_profattr(const void *data, char **rdn,
3020 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
3021 {
3022 	ns_ldap_entry_t	*e;
3023 	int		rc;
3024 	char		trdn[RDNSIZE];
3025 	/* routine specific */
3026 	profstr_t	*ptr;
3027 	int		max_attr = 5;
3028 	static		char *oclist[] = {
3029 			"SolarisProfAttr",
3030 			"top",
3031 			NULL
3032 			};
3033 
3034 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
3035 		return (NS_LDAP_OP_FAILED);
3036 
3037 	*entry = e = __s_mk_entry(oclist, max_attr);
3038 	if (e == NULL)
3039 		return (NS_LDAP_MEMORY);
3040 
3041 	/* Convert the structure */
3042 	ptr = (profstr_t *)data;
3043 
3044 	if (ptr->name == NULL || ptr->name[0] == '\0' || ptr->attr == NULL) {
3045 		__ns_ldap_freeEntry(e);
3046 		*entry = NULL;
3047 		return (NS_LDAP_INVALID_PARAM);
3048 	}
3049 
3050 	/* Create an appropriate rdn */
3051 	(void) snprintf(trdn, RDNSIZE, "cn=%s", ptr->name);
3052 	*rdn = strdup(trdn);
3053 	if (*rdn == NULL) {
3054 		__ns_ldap_freeEntry(e);
3055 		*entry = NULL;
3056 		return (NS_LDAP_MEMORY);
3057 	}
3058 
3059 	rc = __s_add_attr(e, "cn", ptr->name);
3060 	if (rc != NS_LDAP_SUCCESS) {
3061 		__s_cvt_freeEntryRdn(entry, rdn);
3062 		return (rc);
3063 	}
3064 
3065 	rc = __s_add_attr(e, "SolarisAttrKeyValue", ptr->attr);
3066 	if (rc != NS_LDAP_SUCCESS) {
3067 		__s_cvt_freeEntryRdn(entry, rdn);
3068 		return (rc);
3069 	}
3070 
3071 	if (ptr->res1 != NULL) {
3072 		rc = __s_add_attr(e, "SolarisAttrReserved1", ptr->res1);
3073 		if (rc != NS_LDAP_SUCCESS) {
3074 			__s_cvt_freeEntryRdn(entry, rdn);
3075 			return (rc);
3076 		}
3077 	}
3078 
3079 	if (ptr->res2 != NULL) {
3080 		rc = __s_add_attr(e, "SolarisAttrReserved2", ptr->res2);
3081 		if (rc != NS_LDAP_SUCCESS) {
3082 			__s_cvt_freeEntryRdn(entry, rdn);
3083 			return (rc);
3084 		}
3085 	}
3086 
3087 	if (ptr->desc != NULL) {
3088 		rc = __s_add_attr(e, "SolarisAttrLongDesc", ptr->desc);
3089 		if (rc != NS_LDAP_SUCCESS) {
3090 			__s_cvt_freeEntryRdn(entry, rdn);
3091 			return (rc);
3092 		}
3093 	}
3094 
3095 	return (NS_LDAP_SUCCESS);
3096 }
3097 /*
3098  * Conversion:			user_attr
3099  * Input format:		userstr_t
3100  * Exported objectclass:	SolarisUserAttr
3101  */
3102 static int
3103 __s_cvt_userattr(const void *data, char **rdn,
3104 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
3105 {
3106 	ns_ldap_entry_t	*e;
3107 	int		rc;
3108 	char		trdn[RDNSIZE];
3109 	/* routine specific */
3110 	userstr_t	*ptr;
3111 	int		max_attr = 5;
3112 	static		char *oclist[] = {
3113 			"SolarisUserAttr",
3114 			NULL
3115 			};
3116 
3117 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
3118 		return (NS_LDAP_OP_FAILED);
3119 
3120 	*entry = e = __s_mk_entry(oclist, max_attr);
3121 	if (e == NULL)
3122 		return (NS_LDAP_MEMORY);
3123 
3124 	/* Convert the structure */
3125 	ptr = (userstr_t *)data;
3126 
3127 	if (ptr->name == NULL || ptr->name[0] == '\0' ||
3128 	    ptr->attr == NULL) {
3129 		__ns_ldap_freeEntry(e);
3130 		*entry = NULL;
3131 		return (NS_LDAP_INVALID_PARAM);
3132 	}
3133 
3134 	/* Create an appropriate rdn */
3135 	(void) snprintf(trdn, RDNSIZE, "uid=%s", ptr->name);
3136 	*rdn = strdup(trdn);
3137 	if (*rdn == NULL) {
3138 		__ns_ldap_freeEntry(e);
3139 		*entry = NULL;
3140 		return (NS_LDAP_MEMORY);
3141 	}
3142 
3143 	/*
3144 	 * SolarisUserAttr has no uid attribute
3145 	 */
3146 
3147 	rc = __s_add_attr(e, "SolarisAttrKeyValue", ptr->attr);
3148 	if (rc != NS_LDAP_SUCCESS) {
3149 		__s_cvt_freeEntryRdn(entry, rdn);
3150 		return (rc);
3151 	}
3152 
3153 	if (ptr->qualifier != NULL) {
3154 		rc = __s_add_attr(e, "SolarisUserQualifier", ptr->qualifier);
3155 		if (rc != NS_LDAP_SUCCESS) {
3156 			__s_cvt_freeEntryRdn(entry, rdn);
3157 			return (rc);
3158 		}
3159 	}
3160 
3161 	if (ptr->res1 != NULL) {
3162 		rc = __s_add_attr(e, "SolarisAttrReserved1", ptr->res1);
3163 		if (rc != NS_LDAP_SUCCESS) {
3164 			__s_cvt_freeEntryRdn(entry, rdn);
3165 			return (rc);
3166 		}
3167 	}
3168 
3169 	if (ptr->res2 != NULL) {
3170 		rc = __s_add_attr(e, "SolarisAttrReserved2", ptr->res2);
3171 		if (rc != NS_LDAP_SUCCESS) {
3172 			__s_cvt_freeEntryRdn(entry, rdn);
3173 			return (rc);
3174 		}
3175 	}
3176 
3177 	return (NS_LDAP_SUCCESS);
3178 }
3179 /*
3180  * Conversion:			audit_user
3181  * Input format:		au_user_str_t
3182  * Exported objectclass:	SolarisAuditUser
3183  */
3184 static int
3185 __s_cvt_audituser(const void *data, char **rdn,
3186 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
3187 {
3188 	ns_ldap_entry_t	*e;
3189 	int		rc;
3190 	char		trdn[RDNSIZE];
3191 	/* routine specific */
3192 	au_user_str_t	*ptr;
3193 	int		max_attr = 3;
3194 	static		char *oclist[] = {
3195 			"SolarisAuditUser",
3196 			NULL
3197 			};
3198 
3199 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
3200 		return (NS_LDAP_OP_FAILED);
3201 
3202 	*entry = e = __s_mk_entry(oclist, max_attr);
3203 	if (e == NULL)
3204 		return (NS_LDAP_MEMORY);
3205 
3206 	/* Convert the structure */
3207 	ptr = (au_user_str_t *)data;
3208 
3209 	if (ptr->au_name == NULL || ptr->au_name[0] == '\0') {
3210 		__ns_ldap_freeEntry(e);
3211 		*entry = NULL;
3212 		return (NS_LDAP_INVALID_PARAM);
3213 	}
3214 
3215 	/* Create an appropriate rdn */
3216 	(void) snprintf(trdn, RDNSIZE, "uid=%s", ptr->au_name);
3217 	*rdn = strdup(trdn);
3218 	if (*rdn == NULL) {
3219 		__ns_ldap_freeEntry(e);
3220 		*entry = NULL;
3221 		return (NS_LDAP_MEMORY);
3222 	}
3223 
3224 	/*
3225 	 * Solaris AuditUser has no uid attribute
3226 	 */
3227 
3228 	if (ptr->au_always != NULL) {
3229 		rc = __s_add_attr(e, "SolarisAuditAlways", ptr->au_always);
3230 		if (rc != NS_LDAP_SUCCESS) {
3231 			__s_cvt_freeEntryRdn(entry, rdn);
3232 			return (rc);
3233 		}
3234 	}
3235 
3236 	if (ptr->au_never != NULL) {
3237 		rc = __s_add_attr(e, "SolarisAuditNever", ptr->au_never);
3238 		if (rc != NS_LDAP_SUCCESS) {
3239 			__s_cvt_freeEntryRdn(entry, rdn);
3240 			return (rc);
3241 		}
3242 	}
3243 
3244 	return (NS_LDAP_SUCCESS);
3245 }
3246 
3247 /*
3248  * Add Typed Entry Conversion data structures
3249  */
3250 
3251 typedef struct	__ns_cvt_type {
3252 	const char	*service;
3253 	int		flags;
3254 #define	AE		1	/* alway add entries */
3255 	int		(*cvt_rtn)(const void *data,
3256 				char		**rdn,
3257 				ns_ldap_entry_t	**entry,
3258 				ns_ldap_error_t	**errorp);
3259 } __ns_cvt_type_t;
3260 
3261 static __ns_cvt_type_t __s_cvtlist[] = {
3262 	{ NS_LDAP_TYPE_PASSWD,		0, __s_cvt_passwd },
3263 	{ NS_LDAP_TYPE_GROUP,		0, __s_cvt_group },
3264 	{ NS_LDAP_TYPE_HOSTS,		0, __s_cvt_hosts },
3265 	{ NS_LDAP_TYPE_IPNODES,		0, __s_cvt_hosts },
3266 	{ NS_LDAP_TYPE_RPC,		0, __s_cvt_rpc },
3267 	{ NS_LDAP_TYPE_PROTOCOLS,	0, __s_cvt_protocols },
3268 	{ NS_LDAP_TYPE_NETWORKS,	0, __s_cvt_networks },
3269 	{ NS_LDAP_TYPE_NETGROUP,	0, __s_cvt_netgroups },
3270 	{ NS_LDAP_TYPE_ALIASES,		0, __s_cvt_aliases },
3271 	{ NS_LDAP_TYPE_SERVICES,	0, __s_cvt_services },
3272 	{ NS_LDAP_TYPE_ETHERS,		0, __s_cvt_ethers },
3273 	{ NS_LDAP_TYPE_SHADOW,		0, __s_cvt_shadow },
3274 	{ NS_LDAP_TYPE_NETMASKS,	0, __s_cvt_netmasks },
3275 	{ NS_LDAP_TYPE_BOOTPARAMS,	0, __s_cvt_bootparams },
3276 	{ NS_LDAP_TYPE_AUTHATTR,	0, __s_cvt_authattr },
3277 	{ NS_LDAP_TYPE_EXECATTR,	0, __s_cvt_execattr },
3278 	{ NS_LDAP_TYPE_PROFILE,		0, __s_cvt_profattr },
3279 	{ NS_LDAP_TYPE_USERATTR,	AE, __s_cvt_userattr },
3280 	{ NS_LDAP_TYPE_AUTOMOUNT,	0, __s_cvt_auto_mount },
3281 	{ NS_LDAP_TYPE_PUBLICKEY,	AE, __s_cvt_publickey },
3282 	{ NS_LDAP_TYPE_AUUSER,		AE, __s_cvt_audituser },
3283 	{ NULL,				0, NULL },
3284 };
3285 
3286 /*
3287  * Add Typed Entry Routine
3288  */
3289 
3290 /*ARGSUSED*/
3291 int  __ns_ldap_addTypedEntry(
3292 	const char *servicetype,
3293 	const char *basedn,
3294 	const void *data,
3295 	const int  create,
3296 	const ns_cred_t *cred,
3297 	const int flags,
3298 	ns_ldap_error_t **errorp)
3299 {
3300 	char			*rdn = NULL, *fulldn = NULL;
3301 	void			**paramVal = NULL;
3302 	ns_ldap_entry_t 	*entry = NULL;
3303 	const ns_ldap_attr_t	*const *modattrlist;
3304 	ns_ldap_search_desc_t	**sdlist;
3305 	char			**dns = NULL;
3306 	char			trdn[RDNSIZE];
3307 	char			service[BUFSIZE];
3308 	int			rc = 0;
3309 	int			automount = 0;
3310 	int			i, s;
3311 
3312 	rc = NS_LDAP_OP_FAILED;
3313 	for (s = 0; __s_cvtlist[s].service != NULL; s++) {
3314 		if (__s_cvtlist[s].cvt_rtn == NULL)
3315 			continue;
3316 		if (strcasecmp(__s_cvtlist[s].service, servicetype) == 0)
3317 			break;
3318 		/* Or, check if the servicetype is  auto_ */
3319 		if (strcmp(__s_cvtlist[s].service,
3320 		    NS_LDAP_TYPE_AUTOMOUNT) == 0 &&
3321 		    strncasecmp(servicetype, NS_LDAP_TYPE_AUTOMOUNT,
3322 		    sizeof (NS_LDAP_TYPE_AUTOMOUNT) - 1) == 0) {
3323 			automount++;
3324 			break;
3325 		}
3326 	}
3327 	if (__s_cvtlist[s].service == NULL)
3328 		return (rc);
3329 
3330 	/* Convert the data */
3331 	rc = (*__s_cvtlist[s].cvt_rtn)(data, &rdn, &entry, errorp);
3332 	if (rc != NS_LDAP_SUCCESS) {
3333 		__s_cvt_freeEntryRdn(&entry, &rdn);
3334 		return (rc);
3335 	}
3336 	if (rdn == NULL) {
3337 		__ns_ldap_freeEntry(entry);
3338 		return (NS_LDAP_OP_FAILED);
3339 	}
3340 
3341 	if (strcmp(servicetype, "publickey") == 0) {
3342 		struct _ns_pubkey *ptr;
3343 		ptr = (struct _ns_pubkey *)data;
3344 		if (ptr->hostcred == NS_HOSTCRED_TRUE)
3345 			(void) strcpy(service, "hosts");
3346 		else
3347 			(void) strcpy(service, "passwd");
3348 	} else
3349 		(void) strcpy(service, servicetype);
3350 
3351 	/* Create the Full DN */
3352 	if (basedn == NULL) {
3353 		rc = __s_api_get_SSD_from_SSDtoUse_service(service,
3354 		    &sdlist, errorp);
3355 		if (rc != NS_LDAP_SUCCESS) {
3356 			__s_cvt_freeEntryRdn(&entry, &rdn);
3357 			return (rc);
3358 		}
3359 
3360 		if (sdlist == NULL) {
3361 			rc = __s_api_getDNs(&dns, service, errorp);
3362 			if (rc != NS_LDAP_SUCCESS) {
3363 				if (dns) {
3364 					__s_api_free2dArray(dns);
3365 					dns = NULL;
3366 				}
3367 				__s_cvt_freeEntryRdn(&entry, &rdn);
3368 				return (rc);
3369 			}
3370 			(void) snprintf(trdn, RDNSIZE, "%s,%s", rdn, dns[0]);
3371 			__s_api_free2dArray(dns);
3372 		} else {
3373 			if (sdlist[0]->basedn) {
3374 				(void) snprintf(trdn, RDNSIZE, "%s,%s",
3375 				    rdn, sdlist[0]->basedn);
3376 			} else {
3377 				__s_cvt_freeEntryRdn(&entry, &rdn);
3378 				return (NS_LDAP_OP_FAILED);
3379 			}
3380 		}
3381 		i = strlen(trdn) - 1;
3382 		if (trdn[i] == COMMATOK) {
3383 			rc = __ns_ldap_getParam(NS_LDAP_SEARCH_BASEDN_P,
3384 			    &paramVal, errorp);
3385 			if (rc != NS_LDAP_SUCCESS) {
3386 				__s_cvt_freeEntryRdn(&entry, &rdn);
3387 				return (rc);
3388 			}
3389 			i = strlen(trdn) + strlen((char *)(paramVal[0])) + 1;
3390 			fulldn = (char *)calloc(i, 1);
3391 			if (fulldn == NULL) {
3392 				(void) __ns_ldap_freeParam(&paramVal);
3393 				__s_cvt_freeEntryRdn(&entry, &rdn);
3394 				return (NS_LDAP_MEMORY);
3395 			}
3396 			(void) snprintf(fulldn, i, "%s%s", trdn,
3397 			    (char *)(paramVal[0]));
3398 			(void) __ns_ldap_freeParam(&paramVal);
3399 		} else {
3400 			fulldn = strdup(trdn);
3401 			if (fulldn == NULL) {
3402 				__s_cvt_freeEntryRdn(&entry, &rdn);
3403 				return (NS_LDAP_MEMORY);
3404 			}
3405 		}
3406 	} else {
3407 		i = strlen(rdn) + strlen(basedn) + 2;
3408 		fulldn = (char *)calloc(i, 1);
3409 		if (fulldn == NULL) {
3410 			__s_cvt_freeEntryRdn(&entry, &rdn);
3411 			return (NS_LDAP_MEMORY);
3412 		}
3413 		(void) snprintf(fulldn, i, "%s,%s", rdn, basedn);
3414 	}
3415 
3416 	modattrlist = (const ns_ldap_attr_t * const *)entry->attr_pair;
3417 	/* Check to see if the entry exists already */
3418 	/* May need to delete or update first */
3419 
3420 	if (create != 1) {
3421 		/* Modify the entry */
3422 		if ((__s_cvtlist[s].flags & AE) != 0)
3423 			rc = __ns_ldap_addAttr(service, fulldn, modattrlist,
3424 			    cred, flags, errorp);
3425 		else {
3426 			rc = __ns_ldap_repAttr(service, fulldn, modattrlist,
3427 					cred, flags, errorp);
3428 			if (rc == NS_LDAP_INTERNAL && *errorp &&
3429 			    (*errorp)->status == LDAP_NO_SUCH_OBJECT) {
3430 				(void) __ns_ldap_freeError(errorp);
3431 				rc = __ns_ldap_addEntry(service, fulldn,
3432 				    entry, cred, flags, errorp);
3433 			}
3434 		}
3435 	} else {
3436 		/* Add the entry */
3437 		rc = __ns_ldap_addEntry(service, fulldn, entry,
3438 		    cred, flags, errorp);
3439 		if (rc == NS_LDAP_INTERNAL && *errorp &&
3440 		    (*errorp)->status == LDAP_ALREADY_EXISTS &&
3441 		    ((strcmp(service, "ethers") == 0) ||
3442 		    (strcmp(service, "bootparams") == 0))) {
3443 			rc = modify_ethers_bootp(service, rdn, fulldn,
3444 			    modattrlist, cred, flags, errorp);
3445 		}
3446 	}
3447 
3448 	/* Free up entry created by conversion routine */
3449 	if (fulldn != NULL)
3450 		free(fulldn);
3451 	__s_cvt_freeEntryRdn(&entry, &rdn);
3452 	return (rc);
3453 }
3454 
3455 
3456 /*
3457  * Append the default base dn to the dn
3458  * when it ends with ','.
3459  * e.g.
3460  * SSD = service:ou=foo,
3461  */
3462 int
3463 __s_api_append_default_basedn(
3464 	const char *dn,
3465 	char **new_dn,
3466 	int *allocated,
3467 	ns_ldap_error_t **errp) {
3468 
3469 	int		rc = NS_LDAP_SUCCESS, len = 0;
3470 	void		**param = NULL;
3471 	char		*str = NULL;
3472 
3473 	*allocated = FALSE;
3474 	*new_dn = NULL;
3475 
3476 	if (dn == NULL)
3477 		return (NS_LDAP_INVALID_PARAM);
3478 
3479 	rc = __ns_ldap_getParam(NS_LDAP_SEARCH_BASEDN_P,
3480 		(void ***)&param, errp);
3481 
3482 	if (rc != NS_LDAP_SUCCESS) {
3483 		if (param)
3484 			(void) __ns_ldap_freeParam(&param);
3485 		return (rc);
3486 	}
3487 
3488 	len = strlen(dn);
3489 	str = ((char **)param)[0];
3490 	len = len + strlen(str) +1;
3491 	*new_dn = (char *)malloc(len);
3492 	if (*new_dn == NULL) {
3493 		(void) __ns_ldap_freeParam(&param);
3494 		return (NS_LDAP_MEMORY);
3495 	}
3496 	*allocated = TRUE;
3497 
3498 	(void) strcpy(*new_dn, dn);
3499 	(void) strcat(*new_dn, str);
3500 
3501 	(void) __ns_ldap_freeParam(&param);
3502 	return (NS_LDAP_SUCCESS);
3503 }
3504