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 2007 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 	 * separate 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 > MAXUID ||
1366 	    ptr->pw_gid > MAXUID || 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 	(void) sprintf(ibuf, "%u", ptr->pw_uid);
1403 	rc = __s_add_attr(e, "uidNumber", ibuf);
1404 	if (rc != NS_LDAP_SUCCESS) {
1405 		__s_cvt_freeEntryRdn(entry, rdn);
1406 		return (rc);
1407 	}
1408 
1409 	(void) sprintf(ibuf, "%u", ptr->pw_gid);
1410 	rc = __s_add_attr(e, "gidNumber", ibuf);
1411 	if (rc != NS_LDAP_SUCCESS) {
1412 		__s_cvt_freeEntryRdn(entry, rdn);
1413 		return (rc);
1414 	}
1415 	if (ptr->pw_gecos != NULL &&
1416 		ptr->pw_gecos[0] != '\0') {
1417 		rc = __s_add_attr(e, "gecos", ptr->pw_gecos);
1418 		if (rc != NS_LDAP_SUCCESS) {
1419 			__s_cvt_freeEntryRdn(entry, rdn);
1420 			return (rc);
1421 		}
1422 	}
1423 
1424 	rc = __s_add_attr(e, "homeDirectory", ptr->pw_dir);
1425 	if (rc != NS_LDAP_SUCCESS) {
1426 		__s_cvt_freeEntryRdn(entry, rdn);
1427 		return (rc);
1428 	}
1429 	if (ptr->pw_shell != NULL &&
1430 		ptr->pw_shell[0] != '\0') {
1431 		rc = __s_add_attr(e, "loginShell", ptr->pw_shell);
1432 		if (rc != NS_LDAP_SUCCESS) {
1433 			__s_cvt_freeEntryRdn(entry, rdn);
1434 			return (rc);
1435 		}
1436 	}
1437 
1438 	return (NS_LDAP_SUCCESS);
1439 }
1440 
1441 /*
1442  * Conversion:			shadow
1443  * Input format:		struct shadow
1444  * Exported objectclass:	shadowAccount
1445  */
1446 static int
1447 __s_cvt_shadow(const void *data, char **rdn,
1448 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
1449 {
1450 	ns_ldap_entry_t	*e;
1451 	int		rc;
1452 	char		trdn[RDNSIZE];
1453 	/* routine specific */
1454 	struct spwd	*ptr;
1455 	int		max_attr = 10;
1456 	char		ibuf[10];
1457 	static		char *oclist[] = {
1458 			"posixAccount",
1459 			"shadowAccount",
1460 			"account",
1461 			"top",
1462 			NULL
1463 			};
1464 
1465 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
1466 		return (NS_LDAP_OP_FAILED);
1467 	*entry = e = __s_mk_entry(oclist, max_attr);
1468 	if (e == NULL)
1469 		return (NS_LDAP_MEMORY);
1470 
1471 	/* Convert the structure */
1472 	ptr = (struct spwd *)data;
1473 
1474 	if (ptr->sp_namp == NULL) {
1475 		__ns_ldap_freeEntry(e);
1476 		*entry = NULL;
1477 		return (NS_LDAP_INVALID_PARAM);
1478 	}
1479 
1480 	/* Create an appropriate rdn */
1481 	(void) snprintf(trdn, RDNSIZE, "uid=%s", ptr->sp_namp);
1482 	*rdn = strdup(trdn);
1483 	if (*rdn == NULL) {
1484 		__ns_ldap_freeEntry(e);
1485 		*entry = NULL;
1486 		return (NS_LDAP_MEMORY);
1487 	}
1488 
1489 	/* Error check the data and add the attributes */
1490 	rc = __s_add_attr(e, "uid", ptr->sp_namp);
1491 	if (rc != NS_LDAP_SUCCESS) {
1492 		__s_cvt_freeEntryRdn(entry, rdn);
1493 		return (rc);
1494 	}
1495 
1496 	if (ptr->sp_pwdp == NULL) {
1497 		__s_cvt_freeEntryRdn(entry, rdn);
1498 		return (NS_LDAP_INVALID_PARAM);
1499 	} else {
1500 		rc = __s_add_attr(e, "userPassword", ptr->sp_pwdp);
1501 		if (rc != NS_LDAP_SUCCESS) {
1502 			__s_cvt_freeEntryRdn(entry, rdn);
1503 			return (rc);
1504 		}
1505 	}
1506 	if (ptr->sp_lstchg >= 0) {
1507 		(void) sprintf(ibuf, "%d", ptr->sp_lstchg);
1508 		rc = __s_add_attr(e, "shadowLastChange", ibuf);
1509 		if (rc != NS_LDAP_SUCCESS) {
1510 			__s_cvt_freeEntryRdn(entry, rdn);
1511 			return (rc);
1512 		}
1513 	}
1514 	if (ptr->sp_min >= 0) {
1515 		(void) sprintf(ibuf, "%d", ptr->sp_min);
1516 		rc = __s_add_attr(e, "shadowMin", ibuf);
1517 		if (rc != NS_LDAP_SUCCESS) {
1518 			__s_cvt_freeEntryRdn(entry, rdn);
1519 			return (rc);
1520 		}
1521 	}
1522 	if (ptr->sp_max >= 0) {
1523 		(void) sprintf(ibuf, "%d", ptr->sp_max);
1524 		rc = __s_add_attr(e, "shadowMax", ibuf);
1525 		if (rc != NS_LDAP_SUCCESS) {
1526 			__s_cvt_freeEntryRdn(entry, rdn);
1527 			return (rc);
1528 		}
1529 	}
1530 	if (ptr->sp_warn >= 0) {
1531 		(void) sprintf(ibuf, "%d", ptr->sp_warn);
1532 		rc = __s_add_attr(e, "shadowWarning", ibuf);
1533 		if (rc != NS_LDAP_SUCCESS) {
1534 			__s_cvt_freeEntryRdn(entry, rdn);
1535 			return (rc);
1536 		}
1537 	}
1538 	if (ptr->sp_inact >= 0) {
1539 		(void) sprintf(ibuf, "%d", ptr->sp_inact);
1540 		rc = __s_add_attr(e, "shadowInactive", ibuf);
1541 		if (rc != NS_LDAP_SUCCESS) {
1542 			__s_cvt_freeEntryRdn(entry, rdn);
1543 			return (rc);
1544 		}
1545 	}
1546 	if (ptr->sp_expire >= 0) {
1547 		(void) sprintf(ibuf, "%d", ptr->sp_expire);
1548 		rc = __s_add_attr(e, "shadowExpire", ibuf);
1549 		if (rc != NS_LDAP_SUCCESS) {
1550 			__s_cvt_freeEntryRdn(entry, rdn);
1551 			return (rc);
1552 		}
1553 	}
1554 	(void) sprintf(ibuf, "%d", ptr->sp_flag);
1555 	rc = __s_add_attr(e, "shadowFlag", ibuf);
1556 	if (rc != NS_LDAP_SUCCESS) {
1557 		__s_cvt_freeEntryRdn(entry, rdn);
1558 		return (rc);
1559 	}
1560 
1561 	return (NS_LDAP_SUCCESS);
1562 }
1563 
1564 
1565 /*
1566  * Conversion:			group
1567  * Input format:		struct group
1568  * Exported objectclass:	posixGroup
1569  */
1570 static int
1571 __s_cvt_group(const void *data, char **rdn,
1572 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
1573 {
1574 	ns_ldap_entry_t	*e;
1575 	int		rc;
1576 	char		trdn[RDNSIZE];
1577 	/* routine specific */
1578 	struct group	*ptr;
1579 	int		i, j, k;
1580 	char		**nm, **lm;
1581 	int		max_attr = 4;
1582 	char		ibuf[10];
1583 	static		char *oclist[] = {
1584 			"posixGroup",
1585 			"top",
1586 			NULL
1587 			};
1588 
1589 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
1590 		return (NS_LDAP_OP_FAILED);
1591 	*entry = e = __s_mk_entry(oclist, max_attr);
1592 	if (e == NULL)
1593 		return (NS_LDAP_MEMORY);
1594 
1595 	/* Convert the structure */
1596 	ptr = (struct group *)data;
1597 
1598 	if (ptr->gr_name == NULL || ptr->gr_gid > MAXUID) {
1599 		__ns_ldap_freeEntry(e);
1600 		*entry = NULL;
1601 		return (NS_LDAP_INVALID_PARAM);
1602 	}
1603 
1604 	/* Create an appropriate rdn */
1605 	(void) snprintf(trdn, RDNSIZE, "cn=%s", ptr->gr_name);
1606 	*rdn = strdup(trdn);
1607 	if (*rdn == NULL) {
1608 		__ns_ldap_freeEntry(e);
1609 		*entry = NULL;
1610 		return (NS_LDAP_MEMORY);
1611 	}
1612 
1613 	/* Error check the data and add the attributes */
1614 	rc = __s_add_attr(e, "cn", ptr->gr_name);
1615 	if (rc != NS_LDAP_SUCCESS) {
1616 		__s_cvt_freeEntryRdn(entry, rdn);
1617 		return (rc);
1618 	}
1619 
1620 	(void) sprintf(ibuf, "%u", ptr->gr_gid);
1621 	rc = __s_add_attr(e, "gidNumber", ibuf);
1622 	if (rc != NS_LDAP_SUCCESS) {
1623 		__s_cvt_freeEntryRdn(entry, rdn);
1624 		return (rc);
1625 	}
1626 	if (ptr->gr_passwd && ptr->gr_passwd[0] != '\0') {
1627 		rc = __s_add_attr(e, "userPassword", ptr->gr_passwd);
1628 		if (rc != NS_LDAP_SUCCESS) {
1629 			__s_cvt_freeEntryRdn(entry, rdn);
1630 			return (rc);
1631 		}
1632 	}
1633 
1634 	if (ptr->gr_mem && ptr->gr_mem[0]) {
1635 		lm = ptr->gr_mem;
1636 		for (i = 0; *lm; i++, lm++)
1637 			;
1638 		lm = ptr->gr_mem;
1639 		nm = (char **)calloc(i+2, sizeof (char *));
1640 		if (nm == NULL) {
1641 			__s_cvt_freeEntryRdn(entry, rdn);
1642 			return (NS_LDAP_MEMORY);
1643 		}
1644 		for (j = 0; j < i; j++) {
1645 			nm[j] = strdup(lm[j]);
1646 			if (nm[j] == NULL) {
1647 				for (k = 0; k < j; k++)
1648 					free(nm[k]);
1649 				free(nm);
1650 				__s_cvt_freeEntryRdn(entry, rdn);
1651 				return (NS_LDAP_MEMORY);
1652 			}
1653 		}
1654 		rc = __s_add_attrlist(e, "memberUid", nm);
1655 		for (j = 0; j < i; j++) {
1656 			free(nm[j]);
1657 		}
1658 		free(nm);
1659 		nm = NULL;
1660 		if (rc != NS_LDAP_SUCCESS) {
1661 			__s_cvt_freeEntryRdn(entry, rdn);
1662 			return (rc);
1663 		}
1664 	}
1665 
1666 	return (NS_LDAP_SUCCESS);
1667 }
1668 
1669 /*
1670  * Conversion:			hosts
1671  * Input format:		struct hostent
1672  * Exported objectclass:	ipHost
1673  */
1674 static int
1675 __s_cvt_hosts(const void *data, char **rdn,
1676 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
1677 {
1678 	ns_ldap_entry_t	*e;
1679 	int		rc;
1680 	char		trdn[RDNSIZE];
1681 	/* routine specific */
1682 	struct hostent	*ptr;
1683 	int		max_attr = 6;
1684 	int		i, j, k;
1685 	char		**nm, **lm;
1686 	static		char *oclist[] = {
1687 			"ipHost",
1688 			"device",
1689 			"top",
1690 			NULL
1691 			};
1692 
1693 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
1694 		return (NS_LDAP_OP_FAILED);
1695 	*entry = e = __s_mk_entry(oclist, max_attr);
1696 	if (e == NULL)
1697 		return (NS_LDAP_MEMORY);
1698 
1699 	/* Convert the structure */
1700 	ptr = (struct hostent *)data;
1701 
1702 	if (ptr->h_name == NULL ||
1703 	    ptr->h_addr_list == NULL || ptr->h_addr_list[0] == '\0') {
1704 		__ns_ldap_freeEntry(e);
1705 		*entry = NULL;
1706 		return (NS_LDAP_INVALID_PARAM);
1707 	}
1708 
1709 	/* Create an appropriate rdn */
1710 	(void) snprintf(trdn, RDNSIZE, "cn=%s+ipHostNumber=%s",
1711 	    ptr->h_name, ptr->h_addr_list[0]);
1712 	*rdn = strdup(trdn);
1713 	if (*rdn == NULL) {
1714 		__ns_ldap_freeEntry(e);
1715 		*entry = NULL;
1716 		return (NS_LDAP_MEMORY);
1717 	}
1718 
1719 	/* Error check the data and add the attributes */
1720 	if (ptr->h_aliases && ptr->h_aliases[0]) {
1721 		lm = ptr->h_aliases;
1722 		/*
1723 		 * If there is a description, 'i' will contain
1724 		 * the index of the description in the aliases list
1725 		 */
1726 		for (i = 0; *lm && (*lm)[0] != '#'; i++, lm++)
1727 			;
1728 		lm = ptr->h_aliases;
1729 		nm = (char **)calloc(i+2, sizeof (char *));
1730 		if (nm == NULL) {
1731 			__s_cvt_freeEntryRdn(entry, rdn);
1732 			return (NS_LDAP_MEMORY);
1733 		}
1734 		nm[0] = ptr->h_name;
1735 		for (j = 0; j < i; j++)
1736 			nm[j+1] = ptr->h_aliases[j];
1737 
1738 		rc = __s_add_attrlist(e, "cn", nm);
1739 
1740 		if (rc != NS_LDAP_SUCCESS) {
1741 			__s_cvt_freeEntryRdn(entry, rdn);
1742 			free(nm);
1743 			return (rc);
1744 		}
1745 
1746 		if (lm[i] && lm[i][0] == '#') {
1747 			nm[0] = &(lm[i][1]);
1748 			nm[1] = NULL;
1749 			rc = __s_add_attrlist(e, "description", nm);
1750 		}
1751 		free(nm);
1752 		nm = NULL;
1753 		if (rc != NS_LDAP_SUCCESS) {
1754 			__s_cvt_freeEntryRdn(entry, rdn);
1755 			return (rc);
1756 		}
1757 	} else {
1758 		rc = __s_add_attr(e, "cn", ptr->h_name);
1759 		if (rc != NS_LDAP_SUCCESS) {
1760 			__s_cvt_freeEntryRdn(entry, rdn);
1761 			return (rc);
1762 		}
1763 	}
1764 
1765 	if (ptr->h_addr_list && ptr->h_addr_list[0]) {
1766 		lm = ptr->h_addr_list;
1767 		for (i = 0; *lm; i++, lm++)
1768 			;
1769 		lm = ptr->h_addr_list;
1770 		nm = (char **)calloc(i+2, sizeof (char *));
1771 		if (nm == NULL) {
1772 			__s_cvt_freeEntryRdn(entry, rdn);
1773 			return (NS_LDAP_MEMORY);
1774 		}
1775 		for (j = 0; j < i; j++) {
1776 			nm[j] = strdup(lm[j]);
1777 			if (nm[j] == NULL) {
1778 				for (k = 0; k < j; k++)
1779 					free(nm[k]);
1780 				free(nm);
1781 				__s_cvt_freeEntryRdn(entry, rdn);
1782 				return (NS_LDAP_MEMORY);
1783 			}
1784 		}
1785 		rc = __s_add_attrlist(e, "ipHostNumber", nm);
1786 		for (j = 0; j < i; j++) {
1787 			free(nm[j]);
1788 		}
1789 		free(nm);
1790 		nm = NULL;
1791 		if (rc != NS_LDAP_SUCCESS) {
1792 			__s_cvt_freeEntryRdn(entry, rdn);
1793 			return (rc);
1794 		}
1795 	} else {
1796 		__s_cvt_freeEntryRdn(entry, rdn);
1797 		return (NS_LDAP_INVALID_PARAM);
1798 	}
1799 
1800 	return (NS_LDAP_SUCCESS);
1801 }
1802 
1803 /*
1804  * Conversion:			rpc
1805  * Input format:		struct rpcent
1806  * Exported objectclass:	oncRpc
1807  */
1808 static int
1809 __s_cvt_rpc(const void *data, char **rdn,
1810 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
1811 {
1812 	ns_ldap_entry_t	*e;
1813 	int		rc;
1814 	char		trdn[RDNSIZE];
1815 	/* routine specific */
1816 	struct rpcent	*ptr;
1817 	int		max_attr = 3;
1818 	int		i, j;
1819 	char		**nm;
1820 	char		ibuf[10];
1821 	static		char *oclist[] = {
1822 			"oncRpc",
1823 			"top",
1824 			NULL
1825 			};
1826 
1827 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
1828 		return (NS_LDAP_OP_FAILED);
1829 	*entry = e = __s_mk_entry(oclist, max_attr);
1830 	if (e == NULL)
1831 		return (NS_LDAP_MEMORY);
1832 
1833 	/* Convert the structure */
1834 	ptr = (struct rpcent *)data;
1835 
1836 	if (ptr->r_name == NULL || ptr->r_number < 0) {
1837 		__ns_ldap_freeEntry(e);
1838 		*entry = NULL;
1839 		return (NS_LDAP_INVALID_PARAM);
1840 	}
1841 
1842 	/* Create an appropriate rdn */
1843 	(void) snprintf(trdn, RDNSIZE, "cn=%s", ptr->r_name);
1844 	*rdn = strdup(trdn);
1845 	if (*rdn == NULL) {
1846 		__ns_ldap_freeEntry(e);
1847 		*entry = NULL;
1848 		return (NS_LDAP_MEMORY);
1849 	}
1850 
1851 	/* Error check the data and add the attributes */
1852 	if (ptr->r_aliases && ptr->r_aliases[0]) {
1853 		nm = ptr->r_aliases;
1854 		for (i = 0; *nm; i++, nm++)
1855 			;
1856 		nm = (char **)calloc(i+2, sizeof (char *));
1857 		if (nm == NULL) {
1858 			__s_cvt_freeEntryRdn(entry, rdn);
1859 			return (NS_LDAP_MEMORY);
1860 		}
1861 		nm[0] = ptr->r_name;
1862 		for (j = 0; j < i; j++)
1863 			nm[j+1] = ptr->r_aliases[j];
1864 
1865 		rc = __s_add_attrlist(e, "cn", nm);
1866 		free(nm);
1867 		nm = NULL;
1868 		if (rc != NS_LDAP_SUCCESS) {
1869 			__s_cvt_freeEntryRdn(entry, rdn);
1870 			return (rc);
1871 		}
1872 	} else {
1873 		rc = __s_add_attr(e, "cn", ptr->r_name);
1874 		if (rc != NS_LDAP_SUCCESS) {
1875 			__s_cvt_freeEntryRdn(entry, rdn);
1876 			return (rc);
1877 		}
1878 	}
1879 
1880 	if (ptr->r_number >= 0) {
1881 		(void) sprintf(ibuf, "%d", ptr->r_number);
1882 		rc = __s_add_attr(e, "oncRpcNumber", ibuf);
1883 		if (rc != NS_LDAP_SUCCESS) {
1884 			__s_cvt_freeEntryRdn(entry, rdn);
1885 			return (rc);
1886 		}
1887 	}
1888 
1889 	return (NS_LDAP_SUCCESS);
1890 
1891 }
1892 
1893 /*
1894  * Conversion:			protocols
1895  * Input format:		struct protoent
1896  * Exported objectclass:	ipProtocol
1897  */
1898 static int
1899 __s_cvt_protocols(const void *data, char **rdn,
1900 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
1901 {
1902 	ns_ldap_entry_t	*e;
1903 	int		rc;
1904 	char		trdn[RDNSIZE];
1905 	/* routine specific */
1906 	struct protoent	*ptr;
1907 	int		max_attr = 3;
1908 	int		i, j;
1909 	char		ibuf[10];
1910 	char		**nm;
1911 	static		char *oclist[] = {
1912 			"ipProtocol",
1913 			"top",
1914 			NULL
1915 			};
1916 
1917 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
1918 		return (NS_LDAP_OP_FAILED);
1919 	*entry = e = __s_mk_entry(oclist, max_attr);
1920 	if (e == NULL)
1921 		return (NS_LDAP_MEMORY);
1922 
1923 	/* Convert the structure */
1924 	ptr = (struct protoent *)data;
1925 
1926 	if (ptr->p_name == NULL || ptr->p_proto < 0) {
1927 		__ns_ldap_freeEntry(e);
1928 		*entry = NULL;
1929 		return (NS_LDAP_INVALID_PARAM);
1930 	}
1931 
1932 	/* Create an appropriate rdn */
1933 	(void) snprintf(trdn, RDNSIZE, "cn=%s", ptr->p_name);
1934 	*rdn = strdup(trdn);
1935 	if (*rdn == NULL) {
1936 		__ns_ldap_freeEntry(e);
1937 		*entry = NULL;
1938 		return (NS_LDAP_MEMORY);
1939 	}
1940 
1941 	/* Error check the data and add the attributes */
1942 	if (ptr->p_aliases && ptr->p_aliases[0]) {
1943 		nm = ptr->p_aliases;
1944 		for (i = 0; *nm; i++, nm++)
1945 			;
1946 		nm = (char **)calloc(i+2, sizeof (char *));
1947 		if (nm == NULL) {
1948 			__s_cvt_freeEntryRdn(entry, rdn);
1949 			return (NS_LDAP_MEMORY);
1950 		}
1951 		nm[0] = ptr->p_name;
1952 		for (j = 0; j < i; j++)
1953 			nm[j+1] = ptr->p_aliases[j];
1954 
1955 		rc = __s_add_attrlist(e, "cn", nm);
1956 		free(nm);
1957 		nm = NULL;
1958 		if (rc != NS_LDAP_SUCCESS) {
1959 			__s_cvt_freeEntryRdn(entry, rdn);
1960 			return (rc);
1961 		}
1962 	} else {
1963 		rc = __s_add_attr(e, "cn", ptr->p_name);
1964 		if (rc != NS_LDAP_SUCCESS) {
1965 			__s_cvt_freeEntryRdn(entry, rdn);
1966 			return (rc);
1967 		}
1968 	}
1969 
1970 	(void) sprintf(ibuf, "%d", ptr->p_proto);
1971 	rc = __s_add_attr(e, "ipProtocolNumber", ibuf);
1972 	if (rc != NS_LDAP_SUCCESS) {
1973 		__s_cvt_freeEntryRdn(entry, rdn);
1974 		return (rc);
1975 	}
1976 
1977 	return (NS_LDAP_SUCCESS);
1978 
1979 }
1980 
1981 /*
1982  * Conversion:			services
1983  * Input format:		struct servent
1984  * Exported objectclass:	ipService
1985  */
1986 static int
1987 __s_cvt_services(const void *data, char **rdn,
1988 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
1989 {
1990 	ns_ldap_entry_t	*e;
1991 	int		rc;
1992 	char		trdn[RDNSIZE];
1993 	/* routine specific */
1994 	struct servent	*ptr;
1995 	int		max_attr = 4;
1996 	int		i, j;
1997 	char		ibuf[10];
1998 	char		**nm;
1999 	static		char *oclist[] = {
2000 			"ipService",
2001 			"top",
2002 			NULL
2003 			};
2004 
2005 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
2006 		return (NS_LDAP_OP_FAILED);
2007 	*entry = e = __s_mk_entry(oclist, max_attr);
2008 	if (e == NULL)
2009 		return (NS_LDAP_MEMORY);
2010 
2011 	/* Convert the structure */
2012 	ptr = (struct servent *)data;
2013 
2014 	if (ptr->s_name == NULL || ptr->s_port < 0 || ptr->s_proto == '\0') {
2015 		__ns_ldap_freeEntry(e);
2016 		*entry = NULL;
2017 		return (NS_LDAP_INVALID_PARAM);
2018 	}
2019 
2020 	/* Create an appropriate rdn */
2021 	(void) snprintf(trdn, RDNSIZE, "cn=%s+ipServiceProtocol=%s",
2022 				ptr->s_name, ptr->s_proto);
2023 	*rdn = strdup(trdn);
2024 	if (*rdn == NULL) {
2025 		__ns_ldap_freeEntry(e);
2026 		*entry = NULL;
2027 		return (NS_LDAP_MEMORY);
2028 	}
2029 
2030 	/* Error check the data and add the attributes */
2031 	if (ptr->s_aliases && ptr->s_aliases[0]) {
2032 		nm = ptr->s_aliases;
2033 		for (i = 0; *nm; i++, nm++)
2034 			;
2035 		nm = (char **)calloc(i+2, sizeof (char *));
2036 		if (nm == NULL) {
2037 			__s_cvt_freeEntryRdn(entry, rdn);
2038 			return (NS_LDAP_MEMORY);
2039 		}
2040 		nm[0] = ptr->s_name;
2041 		for (j = 0; j < i; j++)
2042 			nm[j+1] = ptr->s_aliases[j];
2043 
2044 		rc = __s_add_attrlist(e, "cn", nm);
2045 		free(nm);
2046 		nm = NULL;
2047 		if (rc != NS_LDAP_SUCCESS) {
2048 			__s_cvt_freeEntryRdn(entry, rdn);
2049 			return (rc);
2050 		}
2051 	} else {
2052 		rc = __s_add_attr(e, "cn", ptr->s_name);
2053 		if (rc != NS_LDAP_SUCCESS) {
2054 			__s_cvt_freeEntryRdn(entry, rdn);
2055 			return (rc);
2056 		}
2057 	}
2058 
2059 	(void) sprintf(ibuf, "%d", ptr->s_port);
2060 	rc = __s_add_attr(e, "ipServicePort", ibuf);
2061 	if (rc != NS_LDAP_SUCCESS) {
2062 		__s_cvt_freeEntryRdn(entry, rdn);
2063 		return (rc);
2064 	}
2065 	rc = __s_add_attr(e, "ipServiceProtocol", ptr->s_proto);
2066 	if (rc != NS_LDAP_SUCCESS) {
2067 		__s_cvt_freeEntryRdn(entry, rdn);
2068 		return (rc);
2069 	}
2070 
2071 	return (NS_LDAP_SUCCESS);
2072 }
2073 
2074 /*
2075  * Conversion:			networks
2076  * Input format:		struct netent
2077  * Exported objectclass:	ipNetwork
2078  */
2079 static int
2080 __s_cvt_networks(const void *data, char **rdn,
2081 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
2082 {
2083 	ns_ldap_entry_t	*e;
2084 	int		rc;
2085 	char		trdn[RDNSIZE];
2086 	/* routine specific */
2087 	struct netent	*ptr;
2088 	int		max_attr = 4;
2089 	int		i, j;
2090 	char		cp[64];
2091 	char		**nm;
2092 	static		char *oclist[] = {
2093 			"ipNetwork",
2094 			"top",
2095 			NULL
2096 			};
2097 
2098 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
2099 		return (NS_LDAP_OP_FAILED);
2100 	*entry = e = __s_mk_entry(oclist, max_attr);
2101 	if (e == NULL)
2102 		return (NS_LDAP_MEMORY);
2103 
2104 	/* Convert the structure */
2105 	ptr = (struct netent *)data;
2106 
2107 	if (ptr->n_name == NULL || ptr->n_net == 0) {
2108 		__ns_ldap_freeEntry(e);
2109 		*entry = NULL;
2110 		return (NS_LDAP_INVALID_PARAM);
2111 	}
2112 
2113 	(void) snprintf(cp, sizeof (cp), "%d.%d.%d.%d",
2114 			(ptr->n_net & 0xFF000000) >> 24,
2115 			(ptr->n_net & 0x00FF0000) >> 16,
2116 			(ptr->n_net & 0x0000FF00) >> 8,
2117 			(ptr->n_net & 0x000000FF));
2118 
2119 	/* Create an appropriate rdn */
2120 	(void) snprintf(trdn, RDNSIZE, "ipNetworkNumber=%s", cp);
2121 	*rdn = strdup(trdn);
2122 	if (*rdn == NULL) {
2123 		__ns_ldap_freeEntry(e);
2124 		*entry = NULL;
2125 		return (NS_LDAP_MEMORY);
2126 	}
2127 
2128 	/* Error check the data and add the attributes */
2129 	if (ptr->n_aliases && ptr->n_aliases[0]) {
2130 		nm = ptr->n_aliases;
2131 		for (i = 0; *nm; i++, nm++)
2132 			;
2133 		nm = (char **)calloc(i+2, sizeof (char *));
2134 		if (nm == NULL) {
2135 			__s_cvt_freeEntryRdn(entry, rdn);
2136 			return (NS_LDAP_MEMORY);
2137 		}
2138 		nm[0] = ptr->n_name;
2139 		for (j = 0; j < i; j++)
2140 			nm[j+1] = ptr->n_aliases[j];
2141 
2142 		rc = __s_add_attrlist(e, "cn", nm);
2143 		free(nm);
2144 		nm = NULL;
2145 		if (rc != NS_LDAP_SUCCESS) {
2146 			__s_cvt_freeEntryRdn(entry, rdn);
2147 			return (rc);
2148 		}
2149 	} else {
2150 		rc = __s_add_attr(e, "cn", ptr->n_name);
2151 		if (rc != NS_LDAP_SUCCESS) {
2152 			__s_cvt_freeEntryRdn(entry, rdn);
2153 			return (rc);
2154 		}
2155 	}
2156 
2157 	rc = __s_add_attr(e, "ipNetworkNumber", cp);
2158 	if (rc != NS_LDAP_SUCCESS) {
2159 		__s_cvt_freeEntryRdn(entry, rdn);
2160 		return (rc);
2161 	}
2162 
2163 	return (NS_LDAP_SUCCESS);
2164 
2165 }
2166 /*
2167  * Conversion:			netmasks
2168  * Input format:		struct _ns_netmasks
2169  * Exported objectclass:	ipNetwork
2170  */
2171 static int
2172 __s_cvt_netmasks(const void *data, char **rdn,
2173 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
2174 {
2175 	ns_ldap_entry_t	*e;
2176 	int		rc;
2177 	char		trdn[RDNSIZE];
2178 	/* routine specific */
2179 	struct _ns_netmasks *ptr;
2180 	int		max_attr = 4;
2181 	static		char *oclist[] = {
2182 			"ipNetwork",
2183 			"top",
2184 			NULL
2185 			};
2186 
2187 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
2188 		return (NS_LDAP_OP_FAILED);
2189 	*entry = e = __s_mk_entry(oclist, max_attr);
2190 	if (e == NULL)
2191 		return (NS_LDAP_MEMORY);
2192 
2193 	/* Convert the structure */
2194 	ptr = (struct _ns_netmasks *)data;
2195 
2196 	if (ptr->netnumber == NULL) {
2197 		__ns_ldap_freeEntry(e);
2198 		*entry = NULL;
2199 		return (NS_LDAP_INVALID_PARAM);
2200 	}
2201 
2202 	/* Create an appropriate rdn */
2203 	(void) snprintf(trdn, RDNSIZE, "ipNetworkNumber=%s", ptr->netnumber);
2204 	*rdn = strdup(trdn);
2205 	if (*rdn == NULL) {
2206 		__ns_ldap_freeEntry(e);
2207 		*entry = NULL;
2208 		return (NS_LDAP_MEMORY);
2209 	}
2210 
2211 	/* Error check the data and add the attributes */
2212 		rc = __s_add_attr(e, "ipNetworkNumber", ptr->netnumber);
2213 		if (rc != NS_LDAP_SUCCESS) {
2214 			__s_cvt_freeEntryRdn(entry, rdn);
2215 			return (rc);
2216 		}
2217 
2218 	if (ptr->netmask != '\0') {
2219 		rc = __s_add_attr(e, "ipNetmaskNumber", ptr->netmask);
2220 		if (rc != NS_LDAP_SUCCESS) {
2221 			__s_cvt_freeEntryRdn(entry, rdn);
2222 			return (rc);
2223 		}
2224 	}
2225 
2226 	return (NS_LDAP_SUCCESS);
2227 
2228 }
2229 /*
2230  * Conversion:			netgroups
2231  * Input format:		struct _ns_netgroups
2232  * Exported objectclass:	nisNetgroup
2233  */
2234 static int
2235 __s_cvt_netgroups(const void *data, char **rdn,
2236 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
2237 {
2238 	ns_ldap_entry_t	*e;
2239 	int		rc;
2240 	char		trdn[RDNSIZE];
2241 	/* routine specific */
2242 	struct _ns_netgroups *ptr;
2243 	int		max_attr = 6;
2244 	int		i, j;
2245 	char		**nm;
2246 	static		char *oclist[] = {
2247 			"nisNetgroup",
2248 			"top",
2249 			NULL
2250 			};
2251 
2252 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
2253 		return (NS_LDAP_OP_FAILED);
2254 	*entry = e = __s_mk_entry(oclist, max_attr);
2255 	if (e == NULL)
2256 		return (NS_LDAP_MEMORY);
2257 
2258 	/* Convert the structure */
2259 	ptr = (struct _ns_netgroups *)data;
2260 
2261 	if (ptr->name == NULL) {
2262 		__ns_ldap_freeEntry(e);
2263 		*entry = NULL;
2264 		return (NS_LDAP_INVALID_PARAM);
2265 	}
2266 
2267 	/* Create an appropriate rdn */
2268 	(void) snprintf(trdn, RDNSIZE, "cn=%s", ptr->name);
2269 	*rdn = strdup(trdn);
2270 	if (*rdn == NULL) {
2271 		__ns_ldap_freeEntry(e);
2272 		*entry = NULL;
2273 		return (NS_LDAP_MEMORY);
2274 	}
2275 
2276 	if (ptr->name != '\0') {
2277 		rc = __s_add_attr(e, "cn", ptr->name);
2278 		if (rc != NS_LDAP_SUCCESS) {
2279 			__s_cvt_freeEntryRdn(entry, rdn);
2280 			return (rc);
2281 		}
2282 	}
2283 
2284 	/* Error check the data and add the attributes */
2285 	if (ptr->triplet && ptr->triplet[0]) {
2286 		nm = ptr->triplet;
2287 		for (i = 0; *nm; i++, nm++)
2288 			;
2289 		nm = (char **)calloc(i+2, sizeof (char *));
2290 		if (nm == NULL) {
2291 			__s_cvt_freeEntryRdn(entry, rdn);
2292 			return (NS_LDAP_MEMORY);
2293 		}
2294 		for (j = 0; j < i; j++)
2295 			nm[j] = ptr->triplet[j];
2296 
2297 		rc = __s_add_attrlist(e, "nisNetgroupTriple", nm);
2298 		free(nm);
2299 		nm = NULL;
2300 		if (rc != NS_LDAP_SUCCESS) {
2301 			__s_cvt_freeEntryRdn(entry, rdn);
2302 			return (rc);
2303 		}
2304 	}
2305 	if (ptr->netgroup && ptr->netgroup[0]) {
2306 		nm = ptr->netgroup;
2307 		for (i = 0; *nm; i++, nm++)
2308 			;
2309 		nm = (char **)calloc(i+2, sizeof (char *));
2310 		if (nm == NULL) {
2311 			__s_cvt_freeEntryRdn(entry, rdn);
2312 			return (NS_LDAP_MEMORY);
2313 		}
2314 		for (j = 0; j < i; j++)
2315 			nm[j] = ptr->netgroup[j];
2316 
2317 		rc = __s_add_attrlist(e, "memberNisNetgroup", nm);
2318 		free(nm);
2319 		nm = NULL;
2320 		if (rc != NS_LDAP_SUCCESS) {
2321 			__s_cvt_freeEntryRdn(entry, rdn);
2322 			return (rc);
2323 		}
2324 	}
2325 	return (NS_LDAP_SUCCESS);
2326 }
2327 /*
2328  * Conversion:			bootparams
2329  * Input format:		struct _ns_bootp
2330  * Exported objectclass:	bootableDevice, device
2331  */
2332 static int
2333 __s_cvt_bootparams(const void *data, char **rdn,
2334 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
2335 {
2336 	ns_ldap_entry_t	*e;
2337 	int		rc;
2338 	char		trdn[RDNSIZE];
2339 	/* routine specific */
2340 	struct _ns_bootp *ptr;
2341 	int		max_attr = 4;
2342 	int		i, j;
2343 	char		**nm;
2344 	static		char *oclist[] = {
2345 			"bootableDevice",
2346 			"device",
2347 			"top",
2348 			NULL
2349 			};
2350 
2351 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
2352 		return (NS_LDAP_OP_FAILED);
2353 	*entry = e = __s_mk_entry(oclist, max_attr);
2354 	if (e == NULL)
2355 		return (NS_LDAP_MEMORY);
2356 
2357 	/* Convert the structure */
2358 	ptr = (struct _ns_bootp *)data;
2359 
2360 	if (ptr->name == NULL) {
2361 		__ns_ldap_freeEntry(e);
2362 		*entry = NULL;
2363 		return (NS_LDAP_INVALID_PARAM);
2364 	}
2365 
2366 	/* Create an appropriate rdn */
2367 	(void) snprintf(trdn, RDNSIZE, "cn=%s", ptr->name);
2368 	*rdn = strdup(trdn);
2369 	if (*rdn == NULL) {
2370 		__ns_ldap_freeEntry(e);
2371 		*entry = NULL;
2372 		return (NS_LDAP_MEMORY);
2373 	}
2374 
2375 	if (ptr->name != '\0') {
2376 		rc = __s_add_attr(e, "cn", ptr->name);
2377 		if (rc != NS_LDAP_SUCCESS) {
2378 			__s_cvt_freeEntryRdn(entry, rdn);
2379 			return (rc);
2380 		}
2381 	}
2382 
2383 	/* Error check the data and add the attributes */
2384 	if (ptr->param && ptr->param[0]) {
2385 		nm = ptr->param;
2386 		for (i = 0; *nm; i++, nm++)
2387 			;
2388 		nm = (char **)calloc(i+2, sizeof (char *));
2389 		if (nm == NULL) {
2390 			__s_cvt_freeEntryRdn(entry, rdn);
2391 			return (NS_LDAP_MEMORY);
2392 		}
2393 		for (j = 0; j < i; j++)
2394 			nm[j] = ptr->param[j];
2395 
2396 		rc = __s_add_attrlist(e, "bootParameter", nm);
2397 		free(nm);
2398 		nm = NULL;
2399 		if (rc != NS_LDAP_SUCCESS) {
2400 			__s_cvt_freeEntryRdn(entry, rdn);
2401 			return (rc);
2402 		}
2403 	}
2404 
2405 	return (NS_LDAP_SUCCESS);
2406 
2407 }
2408 /*
2409  * Conversion:			ethers
2410  * Input format:		struct _ns_ethers
2411  * Exported objectclass:	ieee802Device, device
2412  */
2413 static int
2414 __s_cvt_ethers(const void *data, char **rdn,
2415 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
2416 {
2417 	ns_ldap_entry_t	*e;
2418 	int		rc;
2419 	char		trdn[RDNSIZE];
2420 	/* routine specific */
2421 	struct _ns_ethers	*ptr;
2422 	int		max_attr = 4;
2423 	static		char *oclist[] = {
2424 			"ieee802Device",
2425 			"device",
2426 			"top",
2427 			NULL
2428 			};
2429 
2430 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
2431 		return (NS_LDAP_OP_FAILED);
2432 	*entry = e = __s_mk_entry(oclist, max_attr);
2433 	if (e == NULL)
2434 		return (NS_LDAP_MEMORY);
2435 
2436 	/* Convert the structure */
2437 	ptr = (struct _ns_ethers *)data;
2438 
2439 	if (ptr->name == NULL || ptr->ether == '\0') {
2440 		__ns_ldap_freeEntry(e);
2441 		*entry = NULL;
2442 		return (NS_LDAP_INVALID_PARAM);
2443 	}
2444 
2445 	/* Create an appropriate rdn */
2446 	(void) snprintf(trdn, RDNSIZE, "cn=%s", ptr->name);
2447 	*rdn = strdup(trdn);
2448 	if (*rdn == NULL) {
2449 		__ns_ldap_freeEntry(e);
2450 		*entry = NULL;
2451 		return (NS_LDAP_MEMORY);
2452 	}
2453 
2454 	/* Error check the data and add the attributes */
2455 	rc = __s_add_attr(e, "cn", ptr->name);
2456 	if (rc != NS_LDAP_SUCCESS) {
2457 		__s_cvt_freeEntryRdn(entry, rdn);
2458 		return (rc);
2459 	}
2460 
2461 	rc = __s_add_attr(e, "macAddress", ptr->ether);
2462 	if (rc != NS_LDAP_SUCCESS) {
2463 		__s_cvt_freeEntryRdn(entry, rdn);
2464 		return (rc);
2465 	}
2466 
2467 	return (NS_LDAP_SUCCESS);
2468 }
2469 /*
2470  * This function is used when processing an ethers (objectclass: ieee802Device)
2471  * or a bootparams (objectclass: bootableDevice) entry, and the entry is
2472  * already found in LDAP. Since both ethers and bootparams share the same
2473  * LDAP container, we want to check that the entry found in LDAP is:
2474  * - either the same entry (same cn, same objectclass): we don't do anything
2475  *   in this case
2476  * - or an entry which does not have the objectclass we are interesting in:
2477  *   in this case, we modify the existing entry by adding the relevant
2478  *   objectclass (ieee802Device or bootableDevice) and the relevant attribute(s)
2479  *   from the attribute list previously computing by the relevant conversion
2480  *   function.
2481  *   Note: from conversion functions __s_cvt_ethers() and  __s_cvt_bootparams()
2482  *   we know that there is only 1 more attribute today to add (macAddress
2483  *   or bootParameter)
2484  */
2485 #define	_MAX_ATTR_ETHBOOTP	2
2486 static int
2487 modify_ethers_bootp(
2488 	const char *service,
2489 	const char *rdn,
2490 	const char *fulldn,
2491 	const ns_ldap_attr_t * const *attrlist,
2492 	const ns_cred_t *cred,
2493 	const int flags,
2494 	ns_ldap_error_t	 **errorp)
2495 {
2496 	char	filter[BUFSIZ];
2497 	ns_ldap_result_t *resultp;
2498 	int rc = 0;
2499 	int i;
2500 	ns_ldap_attr_t *new_attrlist[_MAX_ATTR_ETHBOOTP+1];
2501 	ns_ldap_attr_t new_attrlist0;
2502 	char *new_attrvalue0[1];
2503 	const ns_ldap_attr_t	* const *aptr = attrlist;
2504 	ns_ldap_attr_t *aptr2;
2505 	ns_ldap_error_t	 *new_errorp = NULL;
2506 
2507 	if (rdn == NULL || fulldn == NULL || attrlist == NULL ||
2508 		errorp == NULL || service == NULL)
2509 		return (NS_LDAP_OP_FAILED);
2510 
2511 	bzero(&new_attrlist, sizeof (new_attrlist));
2512 	bzero(&new_attrlist0, sizeof (new_attrlist0));
2513 	new_attrlist[0] = &new_attrlist0;
2514 	new_attrlist[0]->attrvalue = new_attrvalue0;
2515 
2516 	new_attrlist[0]->attrname = "objectclass";
2517 	new_attrlist[0]->value_count = 1;
2518 	if (strcasecmp(service, "ethers") == NULL) {
2519 		(void) snprintf(&filter[0], sizeof (filter),
2520 			"(&(objectClass=ieee802Device)(%s))",
2521 			rdn);
2522 		new_attrlist[0]->attrvalue[0] = "ieee802Device";
2523 	} else {
2524 		(void) snprintf(&filter[0], sizeof (filter),
2525 			"(&(objectClass=bootableDevice)(%s))",
2526 			rdn);
2527 		new_attrlist[0]->attrvalue[0] = "bootableDevice";
2528 	}
2529 
2530 	rc =  __ns_ldap_list(service, filter, NULL, (const char **)NULL,
2531 		NULL, NS_LDAP_SCOPE_SUBTREE, &resultp, &new_errorp,
2532 		NULL, NULL);
2533 
2534 	switch (rc) {
2535 	case NS_LDAP_SUCCESS:
2536 		/*
2537 		 * entry already exists for this service
2538 		 * return NS_LDAP_INTERNAL and do not modify the incoming errorp
2539 		 */
2540 		rc = NS_LDAP_INTERNAL;
2541 		break;
2542 	case NS_LDAP_NOTFOUND:
2543 		/*
2544 		 * entry not found with the given objectclasss but entry exists
2545 		 * hence add the relevant attribute (macAddress or bootparams).
2546 		 */
2547 		i = 1;
2548 		while (*aptr && (i < _MAX_ATTR_ETHBOOTP)) {
2549 			/* aptr2 needed here to avoid lint warning */
2550 			aptr2 = (ns_ldap_attr_t *)*aptr++;
2551 			if ((strcasecmp(aptr2->attrname, "cn") != 0) &&
2552 				(strcasecmp(aptr2->attrname,
2553 					"objectclass") != 0)) {
2554 				    new_attrlist[i++] =	(ns_ldap_attr_t *)aptr2;
2555 			}
2556 		}
2557 
2558 		if (i != _MAX_ATTR_ETHBOOTP) {
2559 			/* we haven't found all expected attributes */
2560 			rc = NS_LDAP_OP_FAILED;
2561 			break;
2562 		}
2563 
2564 		aptr = (const ns_ldap_attr_t	* const *) new_attrlist;
2565 		/* clean errorp first */
2566 		(void) __ns_ldap_freeError(errorp);
2567 		rc =  __ns_ldap_addAttr(service, fulldn, aptr, cred, flags,
2568 			errorp);
2569 		break;
2570 	default:
2571 		/*
2572 		 * unexpected error happenned
2573 		 * returning relevant error
2574 		 */
2575 		(void) __ns_ldap_freeError(errorp);
2576 		*errorp = new_errorp;
2577 		break;
2578 	}
2579 
2580 	return (rc);
2581 }
2582 
2583 /*
2584  * Conversion:			publickey
2585  * Input format:		struct _ns_pubkey
2586  * Exported objectclass:	NisKeyObject
2587  */
2588 static int
2589 __s_cvt_publickey(const void *data, char **rdn,
2590 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
2591 {
2592 	ns_ldap_entry_t	*e;
2593 	int		rc;
2594 	char		trdn[RDNSIZE];
2595 	/* routine specific */
2596 	struct _ns_pubkey	*ptr;
2597 	int		max_attr = 3;
2598 	static		char *oclist[] = {
2599 			"NisKeyObject",
2600 			NULL
2601 			};
2602 
2603 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
2604 		return (NS_LDAP_OP_FAILED);
2605 	*entry = e = __s_mk_entry(oclist, max_attr);
2606 	if (e == NULL)
2607 		return (NS_LDAP_MEMORY);
2608 
2609 	/* Convert the structure */
2610 	ptr = (struct _ns_pubkey *)data;
2611 
2612 	if (ptr->name == NULL || ptr->pubkey == '\0' || ptr->privkey == '\0') {
2613 		__ns_ldap_freeEntry(e);
2614 		*entry = NULL;
2615 		return (NS_LDAP_INVALID_PARAM);
2616 	}
2617 
2618 	/* Create an appropriate rdn */
2619 	if (ptr->hostcred == NS_HOSTCRED_FALSE)
2620 		(void) snprintf(trdn, RDNSIZE, "uid=%s", ptr->name);
2621 	else
2622 		(void) snprintf(trdn, RDNSIZE, "cn=%s", ptr->name);
2623 	*rdn = strdup(trdn);
2624 	if (*rdn == NULL) {
2625 		__ns_ldap_freeEntry(e);
2626 		*entry = NULL;
2627 		return (NS_LDAP_MEMORY);
2628 	}
2629 
2630 	/* Error check the data and add the attributes */
2631 
2632 	rc = __s_add_attr(e, "nisPublickey", ptr->pubkey);
2633 	if (rc != NS_LDAP_SUCCESS) {
2634 		__s_cvt_freeEntryRdn(entry, rdn);
2635 		return (rc);
2636 	}
2637 
2638 	rc = __s_add_attr(e, "nisSecretkey", ptr->privkey);
2639 	if (rc != NS_LDAP_SUCCESS) {
2640 		__s_cvt_freeEntryRdn(entry, rdn);
2641 		return (rc);
2642 	}
2643 
2644 	return (NS_LDAP_SUCCESS);
2645 }
2646 /*
2647  * Conversion:			aliases
2648  * Input format:		struct _ns_alias
2649  * Exported objectclass:	mailGroup
2650  */
2651 static int
2652 __s_cvt_aliases(const void *data, char **rdn,
2653 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
2654 {
2655 	ns_ldap_entry_t	*e;
2656 	int		rc;
2657 	char		trdn[RDNSIZE];
2658 	/* routine specific */
2659 	struct _ns_alias *ptr;
2660 	int		max_attr = 4;
2661 	int		i, j;
2662 	char		**nm;
2663 	static		char *oclist[] = {
2664 			"mailGroup",
2665 			"top",
2666 			NULL
2667 			};
2668 
2669 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
2670 		return (NS_LDAP_OP_FAILED);
2671 	*entry = e = __s_mk_entry(oclist, max_attr);
2672 	if (e == NULL)
2673 		return (NS_LDAP_MEMORY);
2674 
2675 	/* Convert the structure */
2676 	ptr = (struct _ns_alias *)data;
2677 
2678 	if (ptr->alias == NULL) {
2679 		__ns_ldap_freeEntry(e);
2680 		*entry = NULL;
2681 		return (NS_LDAP_INVALID_PARAM);
2682 	}
2683 
2684 	/* Create an appropriate rdn */
2685 	(void) snprintf(trdn, RDNSIZE, "cn=%s", ptr->alias);
2686 	*rdn = strdup(trdn);
2687 	if (*rdn == NULL) {
2688 		__ns_ldap_freeEntry(e);
2689 		*entry = NULL;
2690 		return (NS_LDAP_MEMORY);
2691 	}
2692 
2693 	if (ptr->alias != '\0') {
2694 		rc = __s_add_attr(e, "mail", (char *)ptr->alias);
2695 		if (rc != NS_LDAP_SUCCESS) {
2696 			__s_cvt_freeEntryRdn(entry, rdn);
2697 			return (rc);
2698 		}
2699 	}
2700 
2701 	/* Error check the data and add the attributes */
2702 	if (ptr->member && ptr->member[0]) {
2703 		nm = ptr->member;
2704 		for (i = 0; *nm; i++, nm++)
2705 			;
2706 		nm = (char **)calloc(i+2, sizeof (char *));
2707 		if (nm == NULL) {
2708 			__s_cvt_freeEntryRdn(entry, rdn);
2709 			return (NS_LDAP_MEMORY);
2710 		}
2711 		for (j = 0; j < i; j++)
2712 			nm[j] = ptr->member[j];
2713 
2714 		rc = __s_add_attrlist(e, "mgrpRFC822MailMember", nm);
2715 		free(nm);
2716 		nm = NULL;
2717 		if (rc != NS_LDAP_SUCCESS) {
2718 			__s_cvt_freeEntryRdn(entry, rdn);
2719 			return (rc);
2720 		}
2721 	}
2722 
2723 	return (NS_LDAP_SUCCESS);
2724 
2725 }
2726 /*
2727  * Conversion:			automount
2728  * Input format:		struct _ns_automount
2729  * Exported objectclass:	automount
2730  */
2731 static int
2732 __s_cvt_auto_mount(const void *data, char **rdn,
2733 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
2734 {
2735 	ns_ldap_entry_t	*e;
2736 	int		rc;
2737 	char		trdn[RDNSIZE];
2738 	/* routine specific */
2739 	struct _ns_automount *ptr;
2740 	int		max_attr = 6;
2741 	void		**paramVal = NULL;
2742 	char		**mappedschema = NULL;
2743 	int		version1 = 0;
2744 	static		char *oclist[] = {
2745 			NULL,
2746 			"top",
2747 			NULL
2748 			};
2749 
2750 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
2751 		return (NS_LDAP_OP_FAILED);
2752 
2753 	/* determine profile version number */
2754 	rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P, &paramVal, errorp);
2755 	if (paramVal && *paramVal &&
2756 		strcasecmp(*paramVal, NS_LDAP_VERSION_1) == 0)
2757 		version1 = 1;
2758 	if (paramVal)
2759 		(void) __ns_ldap_freeParam(&paramVal);
2760 	if (rc && errorp)
2761 		(void) __ns_ldap_freeError(errorp);
2762 
2763 	/* use old schema for version 1 profiles */
2764 	if (version1)
2765 		oclist[0] = "nisObject";
2766 	else
2767 		oclist[0] = "automount";
2768 
2769 	*entry = e = __s_mk_entry(oclist, max_attr);
2770 	if (e == NULL)
2771 		return (NS_LDAP_MEMORY);
2772 
2773 	/* Convert the structure */
2774 	ptr = (struct _ns_automount *)data;
2775 
2776 	if (ptr->key == NULL || ptr->value == '\0' || ptr->mapname == '\0') {
2777 		__ns_ldap_freeEntry(e);
2778 		*entry = NULL;
2779 		return (NS_LDAP_INVALID_PARAM);
2780 	}
2781 
2782 	/* Create an appropriate rdn */
2783 	(void) snprintf(trdn, RDNSIZE, version1 ? "cn=%s" : "automountKey=%s",
2784 		ptr->key);
2785 	*rdn = strdup(trdn);
2786 	if (*rdn == NULL) {
2787 		__ns_ldap_freeEntry(e);
2788 		*entry = NULL;
2789 		return (NS_LDAP_MEMORY);
2790 	}
2791 
2792 	if (ptr->key != '\0') {
2793 		rc = __s_add_attr(e, version1 ? "cn" : "automountKey",
2794 		(char *)ptr->key);
2795 		if (rc != NS_LDAP_SUCCESS) {
2796 			__s_cvt_freeEntryRdn(entry, rdn);
2797 			return (rc);
2798 		}
2799 	}
2800 
2801 	rc = __s_add_attr(e, version1 ? "nisMapEntry" : "automountInformation",
2802 		(char *)ptr->value);
2803 	if (rc != NS_LDAP_SUCCESS) {
2804 		__s_cvt_freeEntryRdn(entry, rdn);
2805 		return (rc);
2806 	}
2807 
2808 	/*
2809 	 * even for version 2, if automount is mapped to nisObject we
2810 	 * still need 'nisMapName' attribute
2811 	 */
2812 	mappedschema = __ns_ldap_getMappedObjectClass("automount", "automount");
2813 	if (mappedschema && mappedschema[0] &&
2814 		strcasecmp(mappedschema[0], "nisObject") == 0)
2815 		version1 = 1;
2816 	if (mappedschema)
2817 		__s_api_free2dArray(mappedschema);
2818 
2819 	if (version1) {
2820 		rc = __s_add_attr(e, "nisMapName", (char *)ptr->mapname);
2821 		if (rc != NS_LDAP_SUCCESS) {
2822 			__s_cvt_freeEntryRdn(entry, rdn);
2823 			return (rc);
2824 		}
2825 	}
2826 
2827 	return (NS_LDAP_SUCCESS);
2828 }
2829 /*
2830  * Conversion:			auth_attr
2831  * Input format:		authstr_t
2832  * Exported objectclass:	SolarisAuthAttr
2833  */
2834 static int
2835 __s_cvt_authattr(const void *data, char **rdn,
2836 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
2837 {
2838 	ns_ldap_entry_t	*e;
2839 	int		rc;
2840 	char		trdn[RDNSIZE];
2841 	/* routine specific */
2842 	authstr_t	*ptr;
2843 	int		max_attr = 6;
2844 	static		char *oclist[] = {
2845 			"SolarisAuthAttr",
2846 			"top",
2847 			NULL
2848 			};
2849 
2850 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
2851 		return (NS_LDAP_OP_FAILED);
2852 
2853 	*entry = e = __s_mk_entry(oclist, max_attr);
2854 	if (e == NULL)
2855 		return (NS_LDAP_MEMORY);
2856 
2857 	/* Convert the structure */
2858 	ptr = (authstr_t *)data;
2859 
2860 	if (ptr->name == NULL || ptr->name[0] == '\0' || ptr->attr == NULL) {
2861 		__ns_ldap_freeEntry(e);
2862 		*entry = NULL;
2863 		return (NS_LDAP_INVALID_PARAM);
2864 	}
2865 
2866 	/* Create an appropriate rdn */
2867 	(void) snprintf(trdn, RDNSIZE, "cn=%s", ptr->name);
2868 	*rdn = strdup(trdn);
2869 	if (*rdn == NULL) {
2870 		__ns_ldap_freeEntry(e);
2871 		*entry = NULL;
2872 		return (NS_LDAP_MEMORY);
2873 	}
2874 
2875 	rc = __s_add_attr(e, "cn", ptr->name);
2876 	if (rc != NS_LDAP_SUCCESS) {
2877 		__s_cvt_freeEntryRdn(entry, rdn);
2878 		return (rc);
2879 	}
2880 
2881 	rc = __s_add_attr(e, "SolarisAttrKeyValue", ptr->attr);
2882 	if (rc != NS_LDAP_SUCCESS) {
2883 		__s_cvt_freeEntryRdn(entry, rdn);
2884 		return (rc);
2885 	}
2886 
2887 	if (ptr->res1 != NULL) {
2888 		rc = __s_add_attr(e, "SolarisAttrReserved1", ptr->res1);
2889 		if (rc != NS_LDAP_SUCCESS) {
2890 			__s_cvt_freeEntryRdn(entry, rdn);
2891 			return (rc);
2892 		}
2893 	}
2894 
2895 	if (ptr->res2 != NULL) {
2896 		rc = __s_add_attr(e, "SolarisAttrReserved2", ptr->res2);
2897 		if (rc != NS_LDAP_SUCCESS) {
2898 			__s_cvt_freeEntryRdn(entry, rdn);
2899 			return (rc);
2900 		}
2901 	}
2902 
2903 	if (ptr->short_desc != NULL) {
2904 		rc = __s_add_attr(e, "SolarisAttrShortDesc", ptr->short_desc);
2905 		if (rc != NS_LDAP_SUCCESS) {
2906 			__s_cvt_freeEntryRdn(entry, rdn);
2907 			return (rc);
2908 		}
2909 	}
2910 
2911 	if (ptr->long_desc != NULL) {
2912 		rc = __s_add_attr(e, "SolarisAttrLongDesc", ptr->long_desc);
2913 		if (rc != NS_LDAP_SUCCESS) {
2914 			__s_cvt_freeEntryRdn(entry, rdn);
2915 			return (rc);
2916 		}
2917 	}
2918 
2919 	return (NS_LDAP_SUCCESS);
2920 }
2921 /*
2922  * Conversion:			exec_attr
2923  * Input format:		execstr_t
2924  * Exported objectclass:	SolarisExecAttr
2925  */
2926 static int
2927 __s_cvt_execattr(const void *data, char **rdn,
2928 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
2929 {
2930 	ns_ldap_entry_t	*e;
2931 	int		rc;
2932 	char		trdn[RDNSIZE];
2933 	/* routine specific */
2934 	execstr_t	*ptr;
2935 	int		max_attr = 7;
2936 	static		char *oclist[] = {
2937 			"SolarisExecAttr",
2938 			"SolarisProfAttr",
2939 			"top",
2940 			NULL
2941 			};
2942 
2943 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
2944 		return (NS_LDAP_OP_FAILED);
2945 
2946 	*entry = e = __s_mk_entry(oclist, max_attr);
2947 	if (e == NULL)
2948 		return (NS_LDAP_MEMORY);
2949 
2950 	/* Convert the structure */
2951 	ptr = (execstr_t *)data;
2952 
2953 	if (ptr->name == NULL || ptr->name[0] == '\0' ||
2954 	    ptr->policy == NULL || ptr->policy[0] == '\0' ||
2955 	    ptr->type == NULL || ptr->type[0] == '\0' ||
2956 	    ptr->id == NULL || ptr->id[0] == '\0') {
2957 		__ns_ldap_freeEntry(e);
2958 		*entry = NULL;
2959 		return (NS_LDAP_INVALID_PARAM);
2960 	}
2961 
2962 	/* Create an appropriate rdn */
2963 	(void) snprintf(trdn, RDNSIZE, "cn=%s+SolarisKernelSecurityPolicy=%s"
2964 	    "+SolarisProfileType=%s+SolarisProfileId=%s",
2965 	    ptr->name, ptr->policy, ptr->type, ptr->id);
2966 	*rdn = strdup(trdn);
2967 	if (*rdn == NULL) {
2968 		__ns_ldap_freeEntry(e);
2969 		*entry = NULL;
2970 		return (NS_LDAP_MEMORY);
2971 	}
2972 
2973 	rc = __s_add_attr(e, "cn", ptr->name);
2974 	if (rc != NS_LDAP_SUCCESS) {
2975 		__s_cvt_freeEntryRdn(entry, rdn);
2976 		return (rc);
2977 	}
2978 
2979 	rc = __s_add_attr(e, "SolarisKernelSecurityPolicy", ptr->policy);
2980 	if (rc != NS_LDAP_SUCCESS) {
2981 		__s_cvt_freeEntryRdn(entry, rdn);
2982 		return (rc);
2983 	}
2984 
2985 	rc = __s_add_attr(e, "SolarisProfileType", ptr->type);
2986 	if (rc != NS_LDAP_SUCCESS) {
2987 		__s_cvt_freeEntryRdn(entry, rdn);
2988 		return (rc);
2989 	}
2990 
2991 	rc = __s_add_attr(e, "SolarisProfileId", ptr->id);
2992 	if (rc != NS_LDAP_SUCCESS) {
2993 		__s_cvt_freeEntryRdn(entry, rdn);
2994 		return (rc);
2995 	}
2996 
2997 	rc = __s_add_attr(e, "SolarisAttrKeyValue", ptr->attr);
2998 	if (rc != NS_LDAP_SUCCESS) {
2999 		__s_cvt_freeEntryRdn(entry, rdn);
3000 		return (rc);
3001 	}
3002 
3003 	if (ptr->res1 != NULL) {
3004 		rc = __s_add_attr(e, "SolarisAttrRes1", ptr->res1);
3005 		if (rc != NS_LDAP_SUCCESS) {
3006 			__s_cvt_freeEntryRdn(entry, rdn);
3007 			return (rc);
3008 		}
3009 	}
3010 
3011 	if (ptr->res2 != NULL) {
3012 		rc = __s_add_attr(e, "SolarisAttrRes2", ptr->res2);
3013 		if (rc != NS_LDAP_SUCCESS) {
3014 			__s_cvt_freeEntryRdn(entry, rdn);
3015 			return (rc);
3016 		}
3017 	}
3018 
3019 	return (NS_LDAP_SUCCESS);
3020 }
3021 /*
3022  * Conversion:			prof_attr
3023  * Input format:		profstr_t
3024  * Exported objectclass:	SolarisProfAttr
3025  */
3026 static int
3027 __s_cvt_profattr(const void *data, char **rdn,
3028 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
3029 {
3030 	ns_ldap_entry_t	*e;
3031 	int		rc;
3032 	char		trdn[RDNSIZE];
3033 	/* routine specific */
3034 	profstr_t	*ptr;
3035 	int		max_attr = 5;
3036 	static		char *oclist[] = {
3037 			"SolarisProfAttr",
3038 			"top",
3039 			NULL
3040 			};
3041 
3042 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
3043 		return (NS_LDAP_OP_FAILED);
3044 
3045 	*entry = e = __s_mk_entry(oclist, max_attr);
3046 	if (e == NULL)
3047 		return (NS_LDAP_MEMORY);
3048 
3049 	/* Convert the structure */
3050 	ptr = (profstr_t *)data;
3051 
3052 	if (ptr->name == NULL || ptr->name[0] == '\0' || ptr->attr == NULL) {
3053 		__ns_ldap_freeEntry(e);
3054 		*entry = NULL;
3055 		return (NS_LDAP_INVALID_PARAM);
3056 	}
3057 
3058 	/* Create an appropriate rdn */
3059 	(void) snprintf(trdn, RDNSIZE, "cn=%s", ptr->name);
3060 	*rdn = strdup(trdn);
3061 	if (*rdn == NULL) {
3062 		__ns_ldap_freeEntry(e);
3063 		*entry = NULL;
3064 		return (NS_LDAP_MEMORY);
3065 	}
3066 
3067 	rc = __s_add_attr(e, "cn", ptr->name);
3068 	if (rc != NS_LDAP_SUCCESS) {
3069 		__s_cvt_freeEntryRdn(entry, rdn);
3070 		return (rc);
3071 	}
3072 
3073 	rc = __s_add_attr(e, "SolarisAttrKeyValue", ptr->attr);
3074 	if (rc != NS_LDAP_SUCCESS) {
3075 		__s_cvt_freeEntryRdn(entry, rdn);
3076 		return (rc);
3077 	}
3078 
3079 	if (ptr->res1 != NULL) {
3080 		rc = __s_add_attr(e, "SolarisAttrReserved1", ptr->res1);
3081 		if (rc != NS_LDAP_SUCCESS) {
3082 			__s_cvt_freeEntryRdn(entry, rdn);
3083 			return (rc);
3084 		}
3085 	}
3086 
3087 	if (ptr->res2 != NULL) {
3088 		rc = __s_add_attr(e, "SolarisAttrReserved2", ptr->res2);
3089 		if (rc != NS_LDAP_SUCCESS) {
3090 			__s_cvt_freeEntryRdn(entry, rdn);
3091 			return (rc);
3092 		}
3093 	}
3094 
3095 	if (ptr->desc != NULL) {
3096 		rc = __s_add_attr(e, "SolarisAttrLongDesc", ptr->desc);
3097 		if (rc != NS_LDAP_SUCCESS) {
3098 			__s_cvt_freeEntryRdn(entry, rdn);
3099 			return (rc);
3100 		}
3101 	}
3102 
3103 	return (NS_LDAP_SUCCESS);
3104 }
3105 /*
3106  * Conversion:			user_attr
3107  * Input format:		userstr_t
3108  * Exported objectclass:	SolarisUserAttr
3109  */
3110 static int
3111 __s_cvt_userattr(const void *data, char **rdn,
3112 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
3113 {
3114 	ns_ldap_entry_t	*e;
3115 	int		rc;
3116 	char		trdn[RDNSIZE];
3117 	/* routine specific */
3118 	userstr_t	*ptr;
3119 	int		max_attr = 5;
3120 	static		char *oclist[] = {
3121 			"SolarisUserAttr",
3122 			NULL
3123 			};
3124 
3125 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
3126 		return (NS_LDAP_OP_FAILED);
3127 
3128 	*entry = e = __s_mk_entry(oclist, max_attr);
3129 	if (e == NULL)
3130 		return (NS_LDAP_MEMORY);
3131 
3132 	/* Convert the structure */
3133 	ptr = (userstr_t *)data;
3134 
3135 	if (ptr->name == NULL || ptr->name[0] == '\0' ||
3136 	    ptr->attr == NULL) {
3137 		__ns_ldap_freeEntry(e);
3138 		*entry = NULL;
3139 		return (NS_LDAP_INVALID_PARAM);
3140 	}
3141 
3142 	/* Create an appropriate rdn */
3143 	(void) snprintf(trdn, RDNSIZE, "uid=%s", ptr->name);
3144 	*rdn = strdup(trdn);
3145 	if (*rdn == NULL) {
3146 		__ns_ldap_freeEntry(e);
3147 		*entry = NULL;
3148 		return (NS_LDAP_MEMORY);
3149 	}
3150 
3151 	/*
3152 	 * SolarisUserAttr has no uid attribute
3153 	 */
3154 
3155 	rc = __s_add_attr(e, "SolarisAttrKeyValue", ptr->attr);
3156 	if (rc != NS_LDAP_SUCCESS) {
3157 		__s_cvt_freeEntryRdn(entry, rdn);
3158 		return (rc);
3159 	}
3160 
3161 	if (ptr->qualifier != NULL) {
3162 		rc = __s_add_attr(e, "SolarisUserQualifier", ptr->qualifier);
3163 		if (rc != NS_LDAP_SUCCESS) {
3164 			__s_cvt_freeEntryRdn(entry, rdn);
3165 			return (rc);
3166 		}
3167 	}
3168 
3169 	if (ptr->res1 != NULL) {
3170 		rc = __s_add_attr(e, "SolarisAttrReserved1", ptr->res1);
3171 		if (rc != NS_LDAP_SUCCESS) {
3172 			__s_cvt_freeEntryRdn(entry, rdn);
3173 			return (rc);
3174 		}
3175 	}
3176 
3177 	if (ptr->res2 != NULL) {
3178 		rc = __s_add_attr(e, "SolarisAttrReserved2", ptr->res2);
3179 		if (rc != NS_LDAP_SUCCESS) {
3180 			__s_cvt_freeEntryRdn(entry, rdn);
3181 			return (rc);
3182 		}
3183 	}
3184 
3185 	return (NS_LDAP_SUCCESS);
3186 }
3187 /*
3188  * Conversion:			audit_user
3189  * Input format:		au_user_str_t
3190  * Exported objectclass:	SolarisAuditUser
3191  */
3192 static int
3193 __s_cvt_audituser(const void *data, char **rdn,
3194 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
3195 {
3196 	ns_ldap_entry_t	*e;
3197 	int		rc;
3198 	char		trdn[RDNSIZE];
3199 	/* routine specific */
3200 	au_user_str_t	*ptr;
3201 	int		max_attr = 3;
3202 	static		char *oclist[] = {
3203 			"SolarisAuditUser",
3204 			NULL
3205 			};
3206 
3207 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
3208 		return (NS_LDAP_OP_FAILED);
3209 
3210 	*entry = e = __s_mk_entry(oclist, max_attr);
3211 	if (e == NULL)
3212 		return (NS_LDAP_MEMORY);
3213 
3214 	/* Convert the structure */
3215 	ptr = (au_user_str_t *)data;
3216 
3217 	if (ptr->au_name == NULL || ptr->au_name[0] == '\0') {
3218 		__ns_ldap_freeEntry(e);
3219 		*entry = NULL;
3220 		return (NS_LDAP_INVALID_PARAM);
3221 	}
3222 
3223 	/* Create an appropriate rdn */
3224 	(void) snprintf(trdn, RDNSIZE, "uid=%s", ptr->au_name);
3225 	*rdn = strdup(trdn);
3226 	if (*rdn == NULL) {
3227 		__ns_ldap_freeEntry(e);
3228 		*entry = NULL;
3229 		return (NS_LDAP_MEMORY);
3230 	}
3231 
3232 	/*
3233 	 * Solaris AuditUser has no uid attribute
3234 	 */
3235 
3236 	if (ptr->au_always != NULL) {
3237 		rc = __s_add_attr(e, "SolarisAuditAlways", ptr->au_always);
3238 		if (rc != NS_LDAP_SUCCESS) {
3239 			__s_cvt_freeEntryRdn(entry, rdn);
3240 			return (rc);
3241 		}
3242 	}
3243 
3244 	if (ptr->au_never != NULL) {
3245 		rc = __s_add_attr(e, "SolarisAuditNever", ptr->au_never);
3246 		if (rc != NS_LDAP_SUCCESS) {
3247 			__s_cvt_freeEntryRdn(entry, rdn);
3248 			return (rc);
3249 		}
3250 	}
3251 
3252 	return (NS_LDAP_SUCCESS);
3253 }
3254 /*
3255  * Conversion:			tnrhtp
3256  * Input format:		tsol_tpstr_t
3257  * Exported objectclass:	ipTnetTemplate
3258  */
3259 static int
3260 __s_cvt_tnrhtp(const void *data, char **rdn,
3261 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
3262 {
3263 	ns_ldap_entry_t	*e;
3264 	int		rc;
3265 	char		trdn[RDNSIZE];
3266 	/* routine specific */
3267 	int		max_attr = 2;
3268 	tsol_tpstr_t	*ptr;
3269 	static		char *oclist[] = {
3270 			"ipTnetTemplate",
3271 			"top",
3272 			NULL
3273 			};
3274 
3275 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
3276 		return (NS_LDAP_OP_FAILED);
3277 
3278 	*entry = e = __s_mk_entry(oclist, max_attr);
3279 	if (e == NULL)
3280 		return (NS_LDAP_MEMORY);
3281 
3282 	/* Convert the structure */
3283 	ptr = (tsol_tpstr_t *)data;
3284 
3285 	if ((ptr->template == NULL) || (strlen(ptr->template) <= 1)) {
3286 		__ns_ldap_freeEntry(e);
3287 		*entry = NULL;
3288 		return (NS_LDAP_INVALID_PARAM);
3289 	}
3290 
3291 	/* Create an appropriate rdn */
3292 	(void) snprintf(trdn, RDNSIZE, "ipTnetTemplateName=%s", ptr->template);
3293 	*rdn = strdup(trdn);
3294 	if (*rdn == NULL) {
3295 		__ns_ldap_freeEntry(e);
3296 		*entry = NULL;
3297 		return (NS_LDAP_MEMORY);
3298 	}
3299 
3300 	rc = __s_add_attr(e, "ipTnetTemplateName", ptr->template);
3301 	if (rc != NS_LDAP_SUCCESS) {
3302 		__s_cvt_freeEntryRdn(entry, rdn);
3303 		return (rc);
3304 	}
3305 
3306 	rc = __s_add_attr(e, "SolarisAttrKeyValue", ptr->attrs);
3307 	if (rc != NS_LDAP_SUCCESS) {
3308 		__s_cvt_freeEntryRdn(entry, rdn);
3309 		return (rc);
3310 	}
3311 
3312 	return (NS_LDAP_SUCCESS);
3313 }
3314 /*
3315  * Conversion:			tnrhdb
3316  * Input format:		tsol_rhstr_t
3317  * Exported objectclass:	ipTnetHost
3318  */
3319 static int
3320 __s_cvt_tnrhdb(const void *data, char **rdn,
3321 	ns_ldap_entry_t **entry, ns_ldap_error_t **errorp)
3322 {
3323 	ns_ldap_entry_t	*e;
3324 	int		rc;
3325 	char		trdn[RDNSIZE];
3326 	/* routine specific */
3327 	tsol_rhstr_t	*ptr;
3328 	int		max_attr = 2;
3329 	static		char *oclist[] = {
3330 			"ipTnetHost",
3331 			"ipTnetTemplate",
3332 			"top",
3333 			NULL
3334 			};
3335 
3336 	if (data == NULL || rdn == NULL || entry == NULL || errorp == NULL)
3337 		return (NS_LDAP_OP_FAILED);
3338 
3339 	*entry = e = __s_mk_entry(oclist, max_attr);
3340 	if (e == NULL)
3341 		return (NS_LDAP_MEMORY);
3342 
3343 	/* Convert the structure */
3344 	ptr = (tsol_rhstr_t *)data;
3345 
3346 	if ((ptr->address == NULL) || (strlen(ptr->address) <= 1) ||
3347 	    (ptr->template == NULL) || (strlen(ptr->template) <= 1)) {
3348 		__ns_ldap_freeEntry(e);
3349 		*entry = NULL;
3350 		return (NS_LDAP_INVALID_PARAM);
3351 	}
3352 
3353 	/* Create an appropriate rdn */
3354 	(void) snprintf(trdn, RDNSIZE, "ipTnetNumber=%s", ptr->address);
3355 	*rdn = strdup(trdn);
3356 	if (*rdn == NULL) {
3357 		__ns_ldap_freeEntry(e);
3358 		*entry = NULL;
3359 		return (NS_LDAP_MEMORY);
3360 	}
3361 
3362 	rc = __s_add_attr(e, "ipTnetNumber", ptr->address);
3363 	if (rc != NS_LDAP_SUCCESS) {
3364 		__s_cvt_freeEntryRdn(entry, rdn);
3365 		return (rc);
3366 	}
3367 
3368 	rc = __s_add_attr(e, "ipTnetTemplateName", ptr->template);
3369 	if (rc != NS_LDAP_SUCCESS) {
3370 		__s_cvt_freeEntryRdn(entry, rdn);
3371 		return (rc);
3372 	}
3373 
3374 	return (NS_LDAP_SUCCESS);
3375 }
3376 /*
3377  * Add Typed Entry Conversion data structures
3378  */
3379 
3380 typedef struct	__ns_cvt_type {
3381 	const char	*service;
3382 	int		flags;
3383 #define	AE		1	/* alway add entries */
3384 	int		(*cvt_rtn)(const void *data,
3385 				char		**rdn,
3386 				ns_ldap_entry_t	**entry,
3387 				ns_ldap_error_t	**errorp);
3388 } __ns_cvt_type_t;
3389 
3390 static __ns_cvt_type_t __s_cvtlist[] = {
3391 	{ NS_LDAP_TYPE_PASSWD,		0, __s_cvt_passwd },
3392 	{ NS_LDAP_TYPE_GROUP,		0, __s_cvt_group },
3393 	{ NS_LDAP_TYPE_HOSTS,		0, __s_cvt_hosts },
3394 	{ NS_LDAP_TYPE_IPNODES,		0, __s_cvt_hosts },
3395 	{ NS_LDAP_TYPE_RPC,		0, __s_cvt_rpc },
3396 	{ NS_LDAP_TYPE_PROTOCOLS,	0, __s_cvt_protocols },
3397 	{ NS_LDAP_TYPE_NETWORKS,	0, __s_cvt_networks },
3398 	{ NS_LDAP_TYPE_NETGROUP,	0, __s_cvt_netgroups },
3399 	{ NS_LDAP_TYPE_ALIASES,		0, __s_cvt_aliases },
3400 	{ NS_LDAP_TYPE_SERVICES,	0, __s_cvt_services },
3401 	{ NS_LDAP_TYPE_ETHERS,		0, __s_cvt_ethers },
3402 	{ NS_LDAP_TYPE_SHADOW,		0, __s_cvt_shadow },
3403 	{ NS_LDAP_TYPE_NETMASKS,	0, __s_cvt_netmasks },
3404 	{ NS_LDAP_TYPE_BOOTPARAMS,	0, __s_cvt_bootparams },
3405 	{ NS_LDAP_TYPE_AUTHATTR,	0, __s_cvt_authattr },
3406 	{ NS_LDAP_TYPE_EXECATTR,	0, __s_cvt_execattr },
3407 	{ NS_LDAP_TYPE_PROFILE,		0, __s_cvt_profattr },
3408 	{ NS_LDAP_TYPE_USERATTR,	AE, __s_cvt_userattr },
3409 	{ NS_LDAP_TYPE_AUTOMOUNT,	0, __s_cvt_auto_mount },
3410 	{ NS_LDAP_TYPE_PUBLICKEY,	AE, __s_cvt_publickey },
3411 	{ NS_LDAP_TYPE_AUUSER,		AE, __s_cvt_audituser },
3412 	{ NS_LDAP_TYPE_TNRHTP,		0,  __s_cvt_tnrhtp },
3413 	{ NS_LDAP_TYPE_TNRHDB,		0,  __s_cvt_tnrhdb },
3414 	{ NULL,				0, NULL },
3415 };
3416 
3417 /*
3418  * Add Typed Entry Routine
3419  */
3420 
3421 /*ARGSUSED*/
3422 int  __ns_ldap_addTypedEntry(
3423 	const char *servicetype,
3424 	const char *basedn,
3425 	const void *data,
3426 	const int  create,
3427 	const ns_cred_t *cred,
3428 	const int flags,
3429 	ns_ldap_error_t **errorp)
3430 {
3431 	char			*rdn = NULL, *fulldn = NULL;
3432 	void			**paramVal = NULL;
3433 	ns_ldap_entry_t 	*entry = NULL;
3434 	const ns_ldap_attr_t	*const *modattrlist;
3435 	ns_ldap_search_desc_t	**sdlist;
3436 	char			**dns = NULL;
3437 	char			trdn[RDNSIZE];
3438 	char			service[BUFSIZE];
3439 	int			rc = 0;
3440 	int			automount = 0;
3441 	int			i, s;
3442 
3443 	rc = NS_LDAP_OP_FAILED;
3444 	for (s = 0; __s_cvtlist[s].service != NULL; s++) {
3445 		if (__s_cvtlist[s].cvt_rtn == NULL)
3446 			continue;
3447 		if (strcasecmp(__s_cvtlist[s].service, servicetype) == 0)
3448 			break;
3449 		/* Or, check if the servicetype is  auto_ */
3450 		if (strcmp(__s_cvtlist[s].service,
3451 		    NS_LDAP_TYPE_AUTOMOUNT) == 0 &&
3452 		    strncasecmp(servicetype, NS_LDAP_TYPE_AUTOMOUNT,
3453 		    sizeof (NS_LDAP_TYPE_AUTOMOUNT) - 1) == 0) {
3454 			automount++;
3455 			break;
3456 		}
3457 	}
3458 	if (__s_cvtlist[s].service == NULL)
3459 		return (rc);
3460 
3461 	/* Convert the data */
3462 	rc = (*__s_cvtlist[s].cvt_rtn)(data, &rdn, &entry, errorp);
3463 	if (rc != NS_LDAP_SUCCESS) {
3464 		__s_cvt_freeEntryRdn(&entry, &rdn);
3465 		return (rc);
3466 	}
3467 	if (rdn == NULL) {
3468 		__ns_ldap_freeEntry(entry);
3469 		return (NS_LDAP_OP_FAILED);
3470 	}
3471 
3472 	if (strcmp(servicetype, "publickey") == 0) {
3473 		struct _ns_pubkey *ptr;
3474 		ptr = (struct _ns_pubkey *)data;
3475 		if (ptr->hostcred == NS_HOSTCRED_TRUE)
3476 			(void) strcpy(service, "hosts");
3477 		else
3478 			(void) strcpy(service, "passwd");
3479 	} else
3480 		(void) strcpy(service, servicetype);
3481 
3482 	/* Create the Full DN */
3483 	if (basedn == NULL) {
3484 		rc = __s_api_get_SSD_from_SSDtoUse_service(service,
3485 		    &sdlist, errorp);
3486 		if (rc != NS_LDAP_SUCCESS) {
3487 			__s_cvt_freeEntryRdn(&entry, &rdn);
3488 			return (rc);
3489 		}
3490 
3491 		if (sdlist == NULL) {
3492 			rc = __s_api_getDNs(&dns, service, errorp);
3493 			if (rc != NS_LDAP_SUCCESS) {
3494 				if (dns) {
3495 					__s_api_free2dArray(dns);
3496 					dns = NULL;
3497 				}
3498 				__s_cvt_freeEntryRdn(&entry, &rdn);
3499 				return (rc);
3500 			}
3501 			(void) snprintf(trdn, RDNSIZE, "%s,%s", rdn, dns[0]);
3502 			__s_api_free2dArray(dns);
3503 		} else {
3504 			if (sdlist[0]->basedn) {
3505 				(void) snprintf(trdn, RDNSIZE, "%s,%s",
3506 				    rdn, sdlist[0]->basedn);
3507 			} else {
3508 				__s_cvt_freeEntryRdn(&entry, &rdn);
3509 				return (NS_LDAP_OP_FAILED);
3510 			}
3511 		}
3512 		i = strlen(trdn) - 1;
3513 		if (trdn[i] == COMMATOK) {
3514 			rc = __ns_ldap_getParam(NS_LDAP_SEARCH_BASEDN_P,
3515 			    &paramVal, errorp);
3516 			if (rc != NS_LDAP_SUCCESS) {
3517 				__s_cvt_freeEntryRdn(&entry, &rdn);
3518 				return (rc);
3519 			}
3520 			i = strlen(trdn) + strlen((char *)(paramVal[0])) + 1;
3521 			fulldn = (char *)calloc(i, 1);
3522 			if (fulldn == NULL) {
3523 				(void) __ns_ldap_freeParam(&paramVal);
3524 				__s_cvt_freeEntryRdn(&entry, &rdn);
3525 				return (NS_LDAP_MEMORY);
3526 			}
3527 			(void) snprintf(fulldn, i, "%s%s", trdn,
3528 			    (char *)(paramVal[0]));
3529 			(void) __ns_ldap_freeParam(&paramVal);
3530 		} else {
3531 			fulldn = strdup(trdn);
3532 			if (fulldn == NULL) {
3533 				__s_cvt_freeEntryRdn(&entry, &rdn);
3534 				return (NS_LDAP_MEMORY);
3535 			}
3536 		}
3537 	} else {
3538 		i = strlen(rdn) + strlen(basedn) + 2;
3539 		fulldn = (char *)calloc(i, 1);
3540 		if (fulldn == NULL) {
3541 			__s_cvt_freeEntryRdn(&entry, &rdn);
3542 			return (NS_LDAP_MEMORY);
3543 		}
3544 		(void) snprintf(fulldn, i, "%s,%s", rdn, basedn);
3545 	}
3546 
3547 	modattrlist = (const ns_ldap_attr_t * const *)entry->attr_pair;
3548 	/* Check to see if the entry exists already */
3549 	/* May need to delete or update first */
3550 
3551 	if (create != 1) {
3552 		/* Modify the entry */
3553 		/*
3554 		 * To add a shadow-like entry, the addTypedEntry function
3555 		 * would call __ns_ldap_repAttr first, and if server says
3556 		 * LDAP_NO_SUCH_OBJECT, then it tries __ns_ldap_addEntry.
3557 		 * This is to allow a netmask entry to be added even if the
3558 		 * base network entry is not in the directory. It would work
3559 		 * because the difference between the schema for the network
3560 		 * and netmask data contains only MAY attributes.
3561 		 *
3562 		 * But for shadow data, the attributes do not have MUST
3563 		 * attributes the base entry needs, so if the __ns_ldap_addEntry
3564 		 * is executed, it would fail. The real reason, however, is that
3565 		 * the base entry did not exist. So returning
3566 		 * LDAP_OBJECT_CLASS_VIOLATION would just confused.
3567 		 */
3568 		if ((__s_cvtlist[s].flags & AE) != 0)
3569 			rc = __ns_ldap_addAttr(service, fulldn, modattrlist,
3570 			    cred, flags, errorp);
3571 		else {
3572 			rc = __ns_ldap_repAttr(service, fulldn, modattrlist,
3573 					cred, flags, errorp);
3574 			if (rc == NS_LDAP_INTERNAL && *errorp &&
3575 			    (*errorp)->status == LDAP_NO_SUCH_OBJECT) {
3576 				(void) __ns_ldap_freeError(errorp);
3577 				rc = __ns_ldap_addEntry(service, fulldn,
3578 				    entry, cred, flags, errorp);
3579 				if (rc == NS_LDAP_INTERNAL && *errorp &&
3580 				(*errorp)->status ==
3581 					LDAP_OBJECT_CLASS_VIOLATION)
3582 					(*errorp)->status = LDAP_NO_SUCH_OBJECT;
3583 			}
3584 		}
3585 	} else {
3586 		/* Add the entry */
3587 		rc = __ns_ldap_addEntry(service, fulldn, entry,
3588 		    cred, flags, errorp);
3589 		if (rc == NS_LDAP_INTERNAL && *errorp &&
3590 		    (*errorp)->status == LDAP_ALREADY_EXISTS &&
3591 		    ((strcmp(service, "ethers") == 0) ||
3592 		    (strcmp(service, "bootparams") == 0))) {
3593 			rc = modify_ethers_bootp(service, rdn, fulldn,
3594 			    modattrlist, cred, flags, errorp);
3595 		}
3596 	}
3597 
3598 	/* Free up entry created by conversion routine */
3599 	if (fulldn != NULL)
3600 		free(fulldn);
3601 	__s_cvt_freeEntryRdn(&entry, &rdn);
3602 	return (rc);
3603 }
3604 
3605 
3606 /*
3607  * Append the default base dn to the dn
3608  * when it ends with ','.
3609  * e.g.
3610  * SSD = service:ou=foo,
3611  */
3612 int
3613 __s_api_append_default_basedn(
3614 	const char *dn,
3615 	char **new_dn,
3616 	int *allocated,
3617 	ns_ldap_error_t **errp) {
3618 
3619 	int		rc = NS_LDAP_SUCCESS, len = 0;
3620 	void		**param = NULL;
3621 	char		*str = NULL;
3622 
3623 	*allocated = FALSE;
3624 	*new_dn = NULL;
3625 
3626 	if (dn == NULL)
3627 		return (NS_LDAP_INVALID_PARAM);
3628 
3629 	rc = __ns_ldap_getParam(NS_LDAP_SEARCH_BASEDN_P,
3630 		(void ***)&param, errp);
3631 
3632 	if (rc != NS_LDAP_SUCCESS) {
3633 		if (param)
3634 			(void) __ns_ldap_freeParam(&param);
3635 		return (rc);
3636 	}
3637 
3638 	len = strlen(dn);
3639 	str = ((char **)param)[0];
3640 	len = len + strlen(str) +1;
3641 	*new_dn = (char *)malloc(len);
3642 	if (*new_dn == NULL) {
3643 		(void) __ns_ldap_freeParam(&param);
3644 		return (NS_LDAP_MEMORY);
3645 	}
3646 	*allocated = TRUE;
3647 
3648 	(void) strcpy(*new_dn, dn);
3649 	(void) strcat(*new_dn, str);
3650 
3651 	(void) __ns_ldap_freeParam(&param);
3652 	return (NS_LDAP_SUCCESS);
3653 }
3654