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