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