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