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