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