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