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