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