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