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