xref: /titanic_52/usr/src/lib/print/libprint/common/nss_ldap.c (revision 9df258ac654d4990e45ba8bff1661d2d0d3b0d2a)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <string.h>
34 #include <stdarg.h>
35 #include <fcntl.h>
36 #include <syslog.h>
37 #include <errno.h>
38 #include <pwd.h>
39 #include <libintl.h>
40 #include <netdb.h>	/* for rcmd() */
41 
42 #include <ns.h>
43 #include <list.h>
44 #include <misc.h>
45 
46 #define	LDAP_REFERRALS
47 #include <lber.h>
48 #include <ldap.h>
49 #include <sys/systeminfo.h>
50 
51 
52 /*
53  * This modules contains the code required to manipulate printer objects in
54  * a LDAP directory for the Naming Service (NS) switch.
55  * It can "add", "modify" and "delete" the objects on the given ldap server
56  * and in the given NS domain DN, eg. "dc=mkg,dc=sun,dc=com".
57  * Note: printers known to the naming service are contained in the RDN
58  * "ou=printers" under the NS domain DN
59  */
60 
61 #define	PCONTAINER	"ou=printers"
62 
63 /* attribute keywords */
64 #define	ATTR_DN		"dn"
65 #define	ATTR_OCLASS	"objectClass"
66 #define	ATTR_URI	"printer-uri"
67 #define	ATTR_PNAME	"printer-name"
68 #define	ATTR_XRISUP	"printer-xri-supported"
69 #define	ATTR_BSDADDR	"sun-printer-bsdaddr"
70 #define	ATTR_KVP	"sun-printer-kvp"
71 
72 /* objectClass values */
73 #define	OCV_TOP		"top"
74 #define	OCV_PSERVICE	"printerService"
75 #define	OCV_SUNPRT	"sunPrinter"
76 #define	OCV_PABSTRACT	"printerAbstract"
77 
78 /* xri-supported attribute value */
79 #define	AV_UNKNOWN	"unknown"
80 
81 
82 /*
83  * LDAP objectclass atributes that the user can explicity change
84  */
85 
86 static const char *nsl_attr_printerService[] = {
87 	"printer-uri",
88 	"printer-xri-supported",
89 	/* Not allowed "printer-name", */
90 	"printer-natural-language-configured",
91 	"printer-location",
92 	"printer-info",
93 	"printer-more-info",
94 	"printer-make-and-model",
95 	"printer-charset-configured",
96 	"printer-charset-supported",
97 	"printer-generated-natural-language-supported",
98 	"printer-document-format-supported",
99 	"printer-color-supported",
100 	"printer-compression-supported",
101 	"printer-pages-per-minute",
102 	"printer-pages-per-minute-color",
103 	"printer-finishings-supported",
104 	"printer-number-up-supported",
105 	"printer-sides-supported",
106 	"printer-media-supported",
107 	"printer-media-local-supported",
108 	"printer-resolution-supported",
109 	"printer-print-quality-supported",
110 	"printer-job-priority-supported",
111 	"printer-copies-supported",
112 	"printer-job-k-octets-supported",
113 	"printer-current-operator",
114 	"printer-service-person",
115 	"printer-delivery-orientation-supported",
116 	"printer-stacking-order-supported",
117 	"printer-output-features-supported",
118 	(char *)NULL
119 };
120 
121 
122 static const char *nsl_attr_printerIPP[] = {
123 	"printer-ipp-versions-supported",
124 	"printer-multiple-document-jobs-supported",
125 	(char *)NULL
126 };
127 
128 static const char *nsl_attr_sunPrinter[] = {
129 	/* Not allowed "sun-printer-bsdaddr", */
130 	/* Not allowed "sun-printer-kvp", */
131 	(char *)NULL
132 };
133 
134 
135 /*
136  * List of LDAP attributes that user is not allowed to explicitly change
137  */
138 static const char *nsl_attr_notAllowed[] = {
139 	ATTR_DN,
140 	ATTR_OCLASS,		/* objectclass */
141 	ATTR_PNAME,		/* printer-name */
142 	ATTR_BSDADDR,
143 	ATTR_KVP,
144 	(char *)NULL
145 };
146 
147 
148 static NSL_RESULT _connectToLDAP(ns_cred_t *cred, LDAP **ld);
149 static uchar_t *_constructPrinterDN(uchar_t *printerName,
150 				uchar_t *domainDN, char **attrList);
151 static NSL_RESULT _checkPrinterExists(LDAP *ld, uchar_t *printerName,
152 			uchar_t *domainDN, uchar_t **printerDN);
153 static NSL_RESULT _checkPrinterDNExists(LDAP *ld, uchar_t *objectDN);
154 static NSL_RESULT _checkSunPrinter(LDAP *ld, uchar_t *printerDN);
155 static NSL_RESULT _addNewPrinterObject(LDAP *ld, uchar_t *printerName,
156 					uchar_t *domainDN, char **attrList);
157 static NSL_RESULT _modifyPrinterObject(LDAP *ld, uchar_t *printerDN,
158 		uchar_t *printerName, uchar_t *domainDN, char **attrList);
159 static NSL_RESULT _checkAttributes(char **list);
160 static NSL_RESULT _addLDAPmodValue(LDAPMod ***attrs, char *type, char *value);
161 static NSL_RESULT _modLDAPmodValue(LDAPMod ***attrs, char *type, char *value);
162 static NSL_RESULT _constructAddLDAPMod(uchar_t *printerName,
163 					char **attrList,  LDAPMod ***attrs);
164 static NSL_RESULT _constructModLDAPMod(uchar_t *printerName, int sunPrinter,
165 			char **attrList, char ***oldKVPList, LDAPMod ***attrs);
166 static NSL_RESULT _compareURIinDNs(uchar_t *dn1, uchar_t *dn2);
167 static uchar_t *_getThisNSDomainDN(void);
168 static int _popen(char *cmd, char *results, int size);
169 static int _attrInList(char *attr, const char **list);
170 static int _attrInLDAPList(char *attr);
171 static NSL_RESULT _getCurrentKVPValues(LDAP *ld,
172 					uchar_t *objectDN, char ***list);
173 static void _freeList(char ***list);
174 static NSL_RESULT _modAttrKVP(char *value, char ***kvpList);
175 static NSL_RESULT _attrAddKVP(LDAPMod ***attrs, char **kvpList, int kvpExists);
176 static int _manageReferralCredentials(LDAP *ld, char **dn, char **credp,
177 					int *methodp, int freeit);
178 
179 /*
180  * *****************************************************************************
181  *
182  * Function:    ldap_put_printer()
183  *
184  * Description: Action the request to change a printer object in the LDAP
185  *              directory DIT. The object is either added, modified or deleted
186  *              depending on the request's attribute list. A null list indicates
187  *              the request is a delete.
188  *              The object's DN is constructed from the supplied domain DN and
189  *              a check is done to see if the object exists already, if it
190  *              doesn't exist then this is a request to add a new object
191  *              If a URI is given in the attribute list and it is different to
192  *              the existing printing object's DN then the request will be
193  *              rejected.
194  *
195  *
196  * Parameters:
197  * Input:       const ns_printer_t *printer
198  *                - this structure contains the following :
199  *                  char *printerName - name of the printer
200  *                  ns_cred_t *cred - structure containing the ldap host and
201  *                                port, user, password and NS domain DN for the
202  *                                directory server to be updated.
203  *                  char **attrList - pointer to a list of attribute key values
204  *                                for the printer object. If the object does
205  *                                not already exist then this list contains the
206  *                                values for the new object, otherwise this list
207  *                                is a list of attributes to modify. For modify
208  *                                a null attribute value is a attribute delete
209  *                                request. A NULL ptr = delete the object.
210  * Output:      None
211  *
212  * Returns:     int - 0 = request actioned okay
213  *                   !0 = error - see NSL_RESULT codes
214  *
215  * *****************************************************************************
216  */
217 
218 int
219 ldap_put_printer(const ns_printer_t *printer)
220 
221 {
222 	NSL_RESULT result = NSL_OK;
223 	NSL_RESULT printerExists = NSL_ERR_UNKNOWN_PRINTER;
224 	LDAP *ld = NULL;
225 	uchar_t *printerDN = NULL;
226 	uchar_t *domainDN = NULL;
227 	char *printerName = NULL;
228 	ns_cred_t *cred = NULL;
229 	char **attrList = NULL;
230 
231 	/* -------- */
232 
233 	/*
234 	 * Note: the "attributes" list should be null for ldap as the attribute
235 	 * values are passed in the nsdata field
236 	 */
237 
238 	if ((printer != NULL) &&
239 	    (printer->attributes == NULL) && (printer->name != NULL))
240 	{
241 		/* extract required pointer values from structure */
242 
243 		printerName = printer->name;
244 		cred = printer->cred;
245 		if (printer->nsdata != NULL)
246 		{
247 			attrList = ((NS_LDAPDATA *)(printer->nsdata))->attrList;
248 		}
249 
250 		/* connect and bind to the ldap directory server */
251 
252 		result = _connectToLDAP(cred, &ld);
253 		if ((result == NSL_OK) && (ld != NULL))
254 		{
255 			/*
256 			 * check if the NS domain DN was given, if not use the
257 			 * current NS domain
258 			 */
259 
260 			if (cred->domainDN != NULL)
261 			{
262 				domainDN = (uchar_t *)
263 					strdup((char *)cred->domainDN);
264 			}
265 			else
266 			{
267 				/* get DN of current domain */
268 				domainDN = _getThisNSDomainDN();
269 			}
270 
271 			printerExists =
272 				_checkPrinterExists(ld, (uchar_t *)printerName,
273 							domainDN, &printerDN);
274 			if (printerExists != LDAP_SUCCESS)
275 			{
276 				/*
277 				 * could not find the printer by printer-name,
278 				 * but there could be a non sunPrinter object
279 				 * so if the printer-uri was given check if
280 				 * an object for that exists
281 				 */
282 				printerDN =
283 				    _constructPrinterDN(NULL,
284 							domainDN, attrList);
285 				if (printerDN != NULL)
286 				{
287 					printerExists = _checkPrinterDNExists(
288 								ld, printerDN);
289 				}
290 			}
291 #ifdef DEBUG
292 if (printerExists == NSL_OK)
293 {
294 printf("DN found = '%s' for '%s'\n", printerDN, printerName);
295 }
296 #endif
297 
298 			if (attrList == NULL)
299 			{
300 				/*
301 				 * a null list indicates that this is a DELETE
302 				 * object request, so if object exists delete
303 				 * it, otherwise report an error.
304 				 */
305 				if (printerExists == LDAP_SUCCESS)
306 				{
307 				    result = ldap_delete_s(ld,
308 						(char *)printerDN);
309 				    if (result != LDAP_SUCCESS)
310 				    {
311 					result = NSL_ERR_DEL_FAILED;
312 #ifdef DEBUG
313 ldap_perror(ld, "ldap_delete_s failed");
314 #endif
315 				    }
316 				}
317 				else
318 				{
319 				    result = NSL_ERR_UNKNOWN_PRINTER;
320 				}
321 			}
322 			else
323 			{
324 				/*
325 				 * if object exists then this is a
326 				 * modify request otherwise is is an add request
327 				 */
328 
329 				if (printerExists == LDAP_SUCCESS)
330 				{
331 					/*
332 					 * Modify the printer object to
333 					 * give it the new attribute values
334 					 * specified by the user
335 					 */
336 					result =
337 					_modifyPrinterObject(ld, printerDN,
338 						(uchar_t *)printerName,
339 						domainDN, attrList);
340 				}
341 				else
342 				{
343 					/*
344 					 * add new printer object into the
345 					 * ldap directory with the user
346 					 * specified attribute values
347 					 */
348 					result =
349 					    _addNewPrinterObject(ld,
350 						(uchar_t *)printerName,
351 						domainDN, attrList);
352 				}
353 			}
354 
355 			if (printerDN != NULL)
356 			{
357 				free(printerDN);
358 			}
359 			if (domainDN != NULL)
360 			{
361 				free(domainDN);
362 			}
363 
364 			/* disconnect from LDAP server */
365 
366 			(void) ldap_unbind(ld);
367 		}
368 	}
369 
370 	else
371 	{
372 		/* no printerName given */
373 		result = NSL_ERR_INTERNAL;
374 	}
375 
376 	return ((int)result);
377 } /* ldap_put_printer */
378 
379 
380 
381 
382 /*
383  * *****************************************************************************
384  *
385  * Function:    _connectToLDAP()
386  *
387  * Description: Setup the connection and bind to the LDAP directory server.
388  *              The function returns the ldap connection descriptor
389  *
390  * Note:        Currently the native ldap functions do not support secure
391  *              passwords, when this is supported this function will require
392  *              updating to allow the type passed in cred->passwdType to
393  *              be used with the ldap_simple_bind()
394  *
395  * Parameters:
396  * Input:       ns_cred_t *cred - structure containing the credentials (host,
397  *                                port, user and password) required to bind
398  *                                to the directory server to be updated.
399  *              char *printerName - printer name used only for error messages
400  * Output:      LDAP** - ldap connection descriptor pointer. NULL = failed
401  *
402  * Returns:     NSL_RESULT - NSL_OK = connected okay
403  *
404  * *****************************************************************************
405  */
406 
407 static NSL_RESULT
408 _connectToLDAP(ns_cred_t *cred, LDAP **ld)
409 
410 {
411 	NSL_RESULT result = NSL_OK;
412 	int lresult = 0;
413 	int ldapPort = LDAP_PORT;	/* default LDAP port number */
414 	int protoVersion = LDAP_VERSION3;
415 	int derefOption = LDAP_DEREF_NEVER;
416 	int referrals = 1;
417 	char hostname[MAXHOSTNAMELEN];
418 	int tmpMethod = LDAP_AUTH_SIMPLE; /* temp - until its passed in */
419 
420 	/* -------- */
421 
422 	if ((ld == NULL) || (cred == NULL) ||
423 		((cred->passwd == NULL) || (cred->binddn == NULL)))
424 	{
425 		result = NSL_ERR_CREDENTIALS;
426 	}
427 
428 	else
429 	{
430 		*ld = NULL;
431 
432 		/* if host was not given then bind to local host */
433 
434 		if (cred->host != NULL)
435 		{
436 			(void) strlcpy(hostname, cred->host, sizeof (hostname));
437 		}
438 		else
439 		{
440 			(void) sysinfo(SI_HOSTNAME,
441 					hostname, sizeof (hostname));
442 		}
443 
444 		/* initialise the connection to the ldap server */
445 
446 		if (cred->port != 0)
447 		{
448 			ldapPort = cred->port;
449 		}
450 		*ld = ldap_init(hostname, ldapPort);
451 		if (*ld == NULL)
452 		{
453 			/* connection setup failed */
454 			result = NSL_ERR_CONNECT;
455 #ifdef DEBUG
456 (void) perror("ldap_init");
457 #endif
458 		}
459 		else
460 		{
461 			/* set ldap options */
462 
463 			(void) ldap_set_option(*ld, LDAP_OPT_DEREF,
464 						&derefOption);
465 			(void) ldap_set_option(*ld, LDAP_OPT_PROTOCOL_VERSION,
466 						&protoVersion);
467 			(void) ldap_set_option(*ld, LDAP_OPT_REFERRALS,
468 						&referrals);
469 
470 			/* bind to the user DN in the directory */
471 
472 			/* cred->passwdType is currently not supported */
473 
474 			lresult = ldap_simple_bind_s(*ld,
475 						cred->binddn, cred->passwd);
476 
477 			/*
478 			 * before doing anything else, set up the function to
479 			 * call to get authentication details if the
480 			 * ldap update function calls (eg. ldap_add_s()) get a
481 			 * "referral" (to another ldap server) from the
482 			 * original ldap server, eg. if we are trying to do
483 			 * a update on a LDAP replica server.
484 			 */
485 			(void) _manageReferralCredentials(*ld,
486 					&(cred->binddn), &(cred->passwd),
487 					&tmpMethod, -1);
488 			ldap_set_rebind_proc(*ld,
489 			    (LDAP_REBINDPROC_CALLBACK *)
490 				_manageReferralCredentials, NULL);
491 
492 			if (lresult != LDAP_SUCCESS)
493 			{
494 				result = NSL_ERR_BIND;
495 				*ld = NULL;
496 #ifdef DEBUG
497 (void) ldap_perror(*ld, "ldap_simple_bind_s");
498 #endif
499 			}
500 		}
501 	}
502 
503 	return (result);
504 } /* _connectToLDAP */
505 
506 
507 
508 
509 
510 /*
511  * *****************************************************************************
512  *
513  * Function:    _constructPrinterDN()
514  *
515  * Description: Construct the DN for the printer object from its name and NS
516  *              domain DN. If the printer-uri is given in the attrList then
517  *              that is used instead of the printerName.
518  *
519  * Parameters:
520  * Input:       uchar_t *printerName
521  *              uchar_t *domainDN
522  *              char **attrList - this list is searched for printer-uri
523  * Output:      None
524  *
525  * Returns:     uchar_t* - pointer to the DN, this memory is malloced so
526  *                         must be freed using free() when finished with.
527  *
528  * *****************************************************************************
529  */
530 
531 static uchar_t *
532 _constructPrinterDN(uchar_t *printerName, uchar_t *domainDN, char **attrList)
533 
534 {
535 	uchar_t *dn = NULL;
536 	uchar_t *uri = NULL;
537 	char **p = NULL;
538 	int len = 0;
539 
540 	/* ------- */
541 
542 	/* first search for printer-uri in the attribute list */
543 
544 	for (p = attrList; (p != NULL) && (*p != NULL) && (uri == NULL); p++)
545 	{
546 		/* get length of this key word */
547 
548 		for (len = 0; ((*p)[len] != '=') && ((*p)[len] != '\0'); len++);
549 
550 		if ((strncasecmp(*p, ATTR_URI, len) == 0) &&
551 		    (strlen(*p) > len+1))
552 		{
553 			uri = (uchar_t *)&((*p)[len+1]);
554 		}
555 	}
556 
557 
558 	if (domainDN != NULL) {
559 		size_t size;
560 
561 		/* malloc memory for the DN and then construct it */
562 
563 		if ((uri == NULL) && (printerName != NULL))
564 		{
565 			/* use the printerName for the RDN */
566 
567 			size = strlen(ATTR_URI) +
568 			    strlen((char *)printerName) +
569 			    strlen((char *)domainDN) +
570 			    strlen(PCONTAINER) +
571 			    10; /* plus a few extra */
572 
573 			if ((dn = malloc(size)) != NULL)
574 				(void) snprintf((char *)dn, size, "%s=%s,%s,%s",
575 				ATTR_URI, printerName, PCONTAINER, domainDN);
576 		}
577 		else
578 		if (uri != NULL)
579 		{
580 			/* use the URI for the RDN */
581 
582 			size = strlen(ATTR_URI) +
583 			    strlen((char *)uri) +
584 			    strlen((char *)domainDN) +
585 			    strlen(PCONTAINER) +
586 			    10; /* plus a few extra */
587 
588 			if ((dn = malloc(size)) != NULL)
589 				(void) snprintf((char *)dn, size, "%s=%s,%s,%s",
590 				ATTR_URI, uri, PCONTAINER, domainDN);
591 		}
592 
593 		/*
594 		 * else
595 		 * {
596 		 *    printName not given so return null
597 		 * }
598 		 */
599 
600 	}
601 
602 	return (dn);	/* caller must free this memory */
603 } /* _constructPrinterDN */
604 
605 
606 
607 /*
608  * *****************************************************************************
609  *
610  * Function:    _checkPrinterExists()
611  *
612  * Description: Check that the printer object for the printerName exists in the
613  *              directory DIT and then extract the object's DN
614  *              The function uses an exiting ldap connection and does a
615  *              search for the printerName in the supplied domain DN.
616  *
617  * Parameters:
618  * Input:       LDAP *ld             - existing ldap connection descriptor
619  *              uchar_t *printerName - printer name
620  *              uchar_t *domainDN    - DN of domain to search in
621  * Output:      uchar_t **printerDN  - DN of the printer - the caller should
622  *                                     free this memory using free()
623  *
624  * Result:      NSL_RESULT - NSL_OK = object exists
625  *
626  * *****************************************************************************
627  */
628 
629 static NSL_RESULT
630 _checkPrinterExists(LDAP *ld, uchar_t *printerName, uchar_t *domainDN,
631 			uchar_t **printerDN)
632 
633 {
634 	NSL_RESULT result = NSL_ERR_UNKNOWN_PRINTER;
635 	int sresult = LDAP_NO_SUCH_OBJECT;
636 	LDAPMessage *ldapMsg = NULL;
637 	char *requiredAttrs[2] = { ATTR_PNAME, NULL };
638 	LDAPMessage *ldapEntry = NULL;
639 	uchar_t *filter = NULL;
640 	uchar_t *baseDN = NULL;
641 
642 	/* ---------- */
643 
644 	if ((printerName != NULL) && (domainDN != NULL) && (printerDN != NULL))
645 	{
646 		size_t size;
647 
648 		if (printerDN != NULL)
649 		{
650 			*printerDN = NULL;
651 		}
652 
653 		/* search for this Printer in the directory */
654 
655 		size = (3 + strlen((char *)printerName) + strlen(ATTR_PNAME) +
656 			2);
657 
658 		if ((filter = malloc(size)) != NULL)
659 			(void) snprintf((char *)filter, size, "(%s=%s)",
660 			    ATTR_PNAME, (char *)printerName);
661 
662 		size = (strlen((char *)domainDN) + strlen(PCONTAINER) + 5);
663 
664 		if ((baseDN = malloc(size)) != NULL)
665 			(void) snprintf((char *)baseDN, size, "%s,%s",
666 			    PCONTAINER, (char *)domainDN);
667 
668 		sresult = ldap_search_s(ld, (char *)baseDN, LDAP_SCOPE_SUBTREE,
669 				(char *)filter, requiredAttrs, 0, &ldapMsg);
670 		if (sresult == LDAP_SUCCESS)
671 		{
672 			/* check that the object exists and extract its DN */
673 
674 			ldapEntry = ldap_first_entry(ld, ldapMsg);
675 			if (ldapEntry != NULL)
676 			{
677 				/* object found - there should only be one */
678 				result = NSL_OK;
679 
680 				if (printerDN != NULL)
681 				{
682 					*printerDN = (uchar_t *)
683 						ldap_get_dn(ld, ldapEntry);
684 				}
685 			}
686 
687 			(void) ldap_msgfree(ldapMsg);
688 		}
689 	}
690 
691 	else
692 	{
693 		result = NSL_ERR_INTERNAL;
694 	}
695 
696 	return (result);
697 } /* _checkPrinterExists */
698 
699 
700 
701 
702 /*
703  * *****************************************************************************
704  *
705  * Function:    _checkPrinterDNExists()
706  *
707  * Description: Check that the printer object for the DN exists in the
708  *              directory DIT.
709  *              The function uses an exiting ldap connection and does a
710  *              search for the DN supplied.
711  *
712  * Parameters:  LDAP *ld       - existing ldap connection descriptor
713  *              char *objectDN - DN to search for
714  *
715  * Result:      NSL_RESULT - NSL_OK = object exists
716  *
717  * *****************************************************************************
718  */
719 
720 static NSL_RESULT
721 _checkPrinterDNExists(LDAP *ld, uchar_t *objectDN)
722 
723 {
724 	NSL_RESULT result = NSL_ERR_UNKNOWN_PRINTER;
725 	int sresult = LDAP_NO_SUCH_OBJECT;
726 	LDAPMessage *ldapMsg;
727 	char *requiredAttrs[2] = { ATTR_PNAME, NULL };
728 	LDAPMessage *ldapEntry;
729 
730 	/* ---------- */
731 
732 	if ((ld != NULL) && (objectDN != NULL))
733 	{
734 		/* search for this Printer in the directory */
735 
736 		sresult = ldap_search_s(ld, (char *)objectDN, LDAP_SCOPE_BASE,
737 				"(objectclass=*)", requiredAttrs, 0, &ldapMsg);
738 		if (sresult == LDAP_SUCCESS)
739 		{
740 			/* check that the object exists */
741 			ldapEntry = ldap_first_entry(ld, ldapMsg);
742 			if (ldapEntry != NULL)
743 			{
744 				/* object found */
745 				result = NSL_OK;
746 			}
747 
748 			(void) ldap_msgfree(ldapMsg);
749 		}
750 	}
751 
752 	else
753 	{
754 		result = NSL_ERR_INTERNAL;
755 	}
756 
757 	return (result);
758 } /* _checkPrinterDNExists */
759 
760 
761 
762 
763 
764 /*
765  * *****************************************************************************
766  *
767  * Function:    _checkSunPrinter()
768  *
769  * Description: Check that the printer object for the printerDN is a sunPrinter
770  *              ie. it has the required objectclass attribute value.
771  *
772  * Parameters:
773  * Input:       LDAP *ld            - existing ldap connection descriptor
774  * Output:      uchar_t *printerDN  - DN of the printer
775  *
776  * Result:      NSL_RESULT - NSL_OK = object exists and is a sunPrinter
777  *
778  * *****************************************************************************
779  */
780 
781 static NSL_RESULT
782 _checkSunPrinter(LDAP *ld, uchar_t *printerDN)
783 
784 {
785 	NSL_RESULT result = NSL_ERR_UNKNOWN_PRINTER;
786 	int sresult = LDAP_NO_SUCH_OBJECT;
787 	char *requiredAttrs[2] = { ATTR_PNAME, NULL };
788 	LDAPMessage *ldapMsg = NULL;
789 	LDAPMessage *ldapEntry = NULL;
790 	char *filter = NULL;
791 
792 	/* ---------- */
793 
794 	if ((ld != NULL) && (printerDN != NULL))
795 	{
796 		size_t size;
797 
798 		/* search for this Printer in the directory */
799 
800 		size = (3 + strlen(OCV_SUNPRT) + strlen(ATTR_OCLASS) + 2);
801 		if ((filter = malloc(size)) != NULL)
802 			(void) snprintf(filter, size, "(%s=%s)",
803 					ATTR_OCLASS, OCV_SUNPRT);
804 
805 		sresult = ldap_search_s(ld, (char *)printerDN,
806 						LDAP_SCOPE_SUBTREE, filter,
807 						requiredAttrs, 0, &ldapMsg);
808 		if (sresult == LDAP_SUCCESS)
809 		{
810 			/* check that the printer object exists */
811 
812 			ldapEntry = ldap_first_entry(ld, ldapMsg);
813 			if (ldapEntry != NULL)
814 			{
815 				/* object is a sunPrinter */
816 				result = NSL_OK;
817 			}
818 
819 			(void) ldap_msgfree(ldapMsg);
820 		}
821 	}
822 
823 	else
824 	{
825 		result = NSL_ERR_INTERNAL;
826 	}
827 
828 	return (result);
829 } /* _checkSunPrinter */
830 
831 
832 
833 
834 
835 /*
836  * *****************************************************************************
837  *
838  * Function:    _addNewPrinterObject()
839  *
840  * Description: For the given printerName add a printer object into the
841  *              LDAP directory NS domain. The object is created with the
842  *              supplied attribute values. Note: if the printer's uri is
843  *              given that is used as the RDN otherwise the printer's
844  *              name is used as the RDN
845  *
846  * Parameters:
847  * Input:       LDAP    *ld        - existing ldap connection descriptor
848  *              uchar_t *printerName - Name of printer to be added
849  *              uchar_t *domainDN    - DN of the domain to add the printer
850  *              char    **attrList - user specified attribute values list
851  * Output:      None
852  *
853  * Returns:     NSL_RESULT - NSL_OK  = request actioned okay
854  *                           !NSL_OK = error
855  *
856  * *****************************************************************************
857  */
858 
859 static NSL_RESULT
860 _addNewPrinterObject(LDAP *ld, uchar_t *printerName,
861 			uchar_t *domainDN, char **attrList)
862 
863 {
864 	NSL_RESULT result = NSL_ERR_ADD_FAILED;
865 	int lresult = 0;
866 	uchar_t *printerDN = NULL;
867 	LDAPMod **attrs = NULL;
868 
869 	/* ---------- */
870 
871 	if ((ld != NULL) && (printerName != NULL) && (domainDN != NULL) &&
872 		(attrList != NULL) && (attrList[0] != NULL))
873 	{
874 		result = _checkAttributes(attrList);
875 
876 		if (result == NSL_OK)
877 		{
878 			/*
879 			 * construct a DN for the printer from the
880 			 * printerName and printer-uri if given.
881 			 */
882 			printerDN = _constructPrinterDN(printerName,
883 						domainDN, attrList);
884 			if (printerDN != NULL)
885 			{
886 				/*
887 				 * setup attribute values in an LDAPMod
888 				 * structure and then add the object
889 				 */
890 				result = _constructAddLDAPMod(printerName,
891 							attrList, &attrs);
892 				if (result == NSL_OK)
893 				{
894 					lresult = ldap_add_s(ld,
895 						    (char *)printerDN, attrs);
896 					if (lresult == LDAP_SUCCESS)
897 					{
898 						result = NSL_OK;
899 					}
900 					else
901 					{
902 						result = NSL_ERR_ADD_FAILED;
903 #ifdef DEBUG
904 (void) ldap_perror(ld, "ldap_add_s");
905 #endif
906 					}
907 
908 					(void) ldap_mods_free(attrs, 1);
909 				}
910 				free(printerDN);
911 			}
912 
913 			else
914 			{
915 				result = NSL_ERR_INTERNAL;
916 			}
917 		}
918 	}
919 
920 	else
921 	{
922 		result = NSL_ERR_INTERNAL;
923 	}
924 
925 	return (result);
926 } /* _addNewPrinterObject */
927 
928 
929 
930 
931 
932 
933 /*
934  * *****************************************************************************
935  *
936  * Function:    _modifyPrinterObject()
937  *
938  * Description: Modify the given LDAP printer object to set the new attributes
939  *              in the attribute list. If the printer's URI (specified in the
940  *              attrList) changes the URI of the object the request is rejected.
941  *
942  * Parameters:
943  * Input:       LDAP    *ld        - existing ldap connection descriptor
944  *              uchar_t *printerDN - DN of printer object to modify
945  *              uchar_t *printerName - Name of printer to be modified
946  *              uchar_t *domainDN    - DN of the domain the printer is in
947  *              char    **attrList - user specified attribute values list
948  * Output:      None
949  *
950  * Returns:     NSL_RESULT - NSL_OK = object modified okay
951  *
952  * *****************************************************************************
953  */
954 
955 static NSL_RESULT
956 _modifyPrinterObject(LDAP *ld, uchar_t *printerDN,
957 		uchar_t *printerName, uchar_t *domainDN, char **attrList)
958 
959 {
960 	NSL_RESULT result = NSL_ERR_INTERNAL;
961 	int lresult = 0;
962 	int sunPrinter = 0;
963 	uchar_t *uriDN = NULL;
964 	LDAPMod **attrs = NULL;
965 	char **kvpList = NULL;
966 
967 	/* ---------- */
968 
969 	if ((ld != NULL) && (printerDN != NULL) && (printerName != NULL) &&
970 	    (domainDN != NULL) && (attrList != NULL) && (attrList[0] != NULL))
971 	{
972 		result = _checkAttributes(attrList);
973 
974 		if (result == NSL_OK)
975 		{
976 			/*
977 			 * The user may have requested that the printer object
978 			 * be given a new URI RDN, so construct a DN for the
979 			 * printer from the printerName or the printer-uri (if
980 			 * given).
981 			 */
982 			uriDN = _constructPrinterDN(NULL, domainDN, attrList);
983 
984 			/*
985 			 * compare the 2 DNs to see if the URI has changed,
986 			 * if uriDN is null then the DN hasn't changed
987 			 */
988 			if ((uriDN == NULL) || ((uriDN != NULL) &&
989 			    (_compareURIinDNs(printerDN, uriDN) == NSL_OK)))
990 			{
991 				/*
992 				 * setup the modify object LDAPMod
993 				 * structure and then do the modify
994 				 */
995 
996 				if (_checkSunPrinter(ld, printerDN) == NSL_OK)
997 				{
998 					sunPrinter = 1;
999 				}
1000 
1001 				(void) _getCurrentKVPValues(ld,
1002 							printerDN, &kvpList);
1003 
1004 				result = _constructModLDAPMod(printerName,
1005 							sunPrinter, attrList,
1006 							&kvpList, &attrs);
1007 				_freeList(&kvpList);
1008 
1009 				if ((result == NSL_OK) && (attrs != NULL))
1010 				{
1011 					lresult = ldap_modify_s(
1012 						ld, (char *)printerDN, attrs);
1013 					if (lresult == LDAP_SUCCESS)
1014 					{
1015 						result = NSL_OK;
1016 					}
1017 					else
1018 					{
1019 						result = NSL_ERR_MOD_FAILED;
1020 #ifdef DEBUG
1021 (void) ldap_perror(ld, "ldap_modify_s");
1022 #endif
1023 					}
1024 
1025 					(void) ldap_mods_free(attrs, 1);
1026 				}
1027 			}
1028 			else
1029 			{
1030 				/*
1031 				 * printer-uri name change has been requested
1032 				 * this is NOT allowed as it requires that
1033 				 * a new printer object is created
1034 				 */
1035 				result = NSL_ERR_RENAME;  /* NOT ALLOWED */
1036 			}
1037 
1038 			if (uriDN != NULL)
1039 			{
1040 				free(uriDN);
1041 			}
1042 		}
1043 	}
1044 
1045 	return (result);
1046 } /* _modifyPrinterObject */
1047 
1048 
1049 
1050 
1051 /*
1052  * *****************************************************************************
1053  *
1054  * Function:    _checkAttributes()
1055  *
1056  * Description: Check that the given attribute lists does not contain any
1057  *              key words that are not allowed.
1058  *
1059  * Parameters:
1060  * Input:       char **list - attribute list to check
1061  * Output:      None
1062  *
1063  * Returns:     NSL_RESULT - NSL_OK = checked okay
1064  *
1065  * *****************************************************************************
1066  */
1067 
1068 static NSL_RESULT
1069 _checkAttributes(char **list)
1070 
1071 {
1072 	NSL_RESULT result = NSL_OK;
1073 	int len = 0;
1074 	char *attr = NULL;
1075 	char **p = NULL;
1076 
1077 	/* ------ */
1078 
1079 	for (p = list; (p != NULL) && (*p != NULL) && (result == NSL_OK); p++)
1080 	{
1081 		/* get length of this key word */
1082 
1083 		for (len = 0; ((*p)[len] != '=') && ((*p)[len] != '\0'); len++);
1084 
1085 		/* check if the key word is allowed */
1086 
1087 		if (strncasecmp(*p, ATTR_KVP, len) == 0)
1088 		{
1089 			/* not supported through this interface */
1090 			result = NSL_ERR_KVP;
1091 		}
1092 		else
1093 		if (strncasecmp(*p, ATTR_BSDADDR, len) == 0)
1094 		{
1095 			/* not supported through this interface */
1096 			result = NSL_ERR_BSDADDR;
1097 		}
1098 		else
1099 		if (strncasecmp(*p, ATTR_PNAME, len) == 0)
1100 		{
1101 			/* not supported through this interface */
1102 			result = NSL_ERR_PNAME;
1103 		}
1104 		else
1105 		{
1106 			/* check for any others */
1107 
1108 			attr = strdup(*p);
1109 			attr[len] = '\0'; /* terminate the key */
1110 
1111 			if (_attrInList(attr, nsl_attr_notAllowed))
1112 			{
1113 				result = NSL_ERR_NOTALLOWED;
1114 			}
1115 		}
1116 
1117 	}
1118 
1119 	return (result);
1120 } /* _checkAttributes */
1121 
1122 
1123 
1124 
1125 /*
1126  * *****************************************************************************
1127  *
1128  * Function:    _addLDAPmodValue()
1129  *
1130  * Description: Add the given attribute and its value to the LDAPMod array.
1131  *              If this is the first entry in the array then create it.
1132  *
1133  * Parameters:
1134  * Input:       LDAPMod ***attrs  - array to update
1135  *              char *type        - attribute to add into array
1136  *              char *value       - attribute value
1137  * Output:      None
1138  *
1139  * Returns:     NSL_RESULT - NSL_OK = added okay
1140  *
1141  * *****************************************************************************
1142  */
1143 
1144 static NSL_RESULT
1145 _addLDAPmodValue(LDAPMod ***attrs, char *type, char *value)
1146 
1147 {
1148 	int i = 0;
1149 	int j = 0;
1150 	NSL_RESULT result = NSL_OK;
1151 
1152 	/* ---------- */
1153 
1154 	if ((attrs != NULL) && (type != NULL) && (value != NULL))
1155 	{
1156 #ifdef DEBUG
1157 printf("_addLDAPmodValue() type='%s', value='%s'\n", type, value);
1158 #endif
1159 		/* search the existing LDAPMod array for the attribute */
1160 
1161 		for (i = 0; *attrs != NULL && (*attrs)[i] != NULL; i++)
1162 		{
1163 			if (strcasecmp((*attrs)[i]->mod_type, type) == 0)
1164 			{
1165 				break;
1166 			}
1167 		}
1168 
1169 		if (*attrs == NULL)
1170 		{
1171 			/* array empty so create it */
1172 
1173 			*attrs = (LDAPMod **)calloc(1, 2 * sizeof (LDAPMod *));
1174 			if (*attrs != NULL)
1175 			{
1176 				i = 0;
1177 			}
1178 			else
1179 			{
1180 				result = NSL_ERR_MEMORY;
1181 			}
1182 
1183 		}
1184 		else
1185 		if ((*attrs)[i] == NULL)
1186 		{
1187 			*attrs = (LDAPMod **)
1188 				realloc(*attrs, (i+2) * sizeof (LDAPMod *));
1189 			if (*attrs == NULL)
1190 			{
1191 				result = NSL_ERR_MEMORY;
1192 			}
1193 		}
1194 	}
1195 	else
1196 	{
1197 		result = NSL_ERR_INTERNAL;
1198 	}
1199 
1200 	if (result == NSL_OK)
1201 	{
1202 		if ((*attrs)[i] == NULL)
1203 		{
1204 			/* We've got a new slot. Create the new mod. */
1205 
1206 			(*attrs)[i] = (LDAPMod *) malloc(sizeof (LDAPMod));
1207 			if ((*attrs)[i] != NULL)
1208 			{
1209 				(*attrs)[i]->mod_op = LDAP_MOD_ADD;
1210 				(*attrs)[i]->mod_type = strdup(type);
1211 				(*attrs)[i]->mod_values = (char **)
1212 						malloc(2 * sizeof (char *));
1213 				if ((*attrs)[i]->mod_values  != NULL)
1214 				{
1215 					(*attrs)[i]->mod_values[0] =
1216 								strdup(value);
1217 					(*attrs)[i]->mod_values[1] = NULL;
1218 					(*attrs)[i+1] = NULL;
1219 				}
1220 				else
1221 				{
1222 					result = NSL_ERR_MEMORY;
1223 				}
1224 			}
1225 			else
1226 			{
1227 				result = NSL_ERR_MEMORY;
1228 			}
1229 		}
1230 
1231 		else
1232 		{
1233 			/* Found an existing entry so add value to it */
1234 
1235 			for (j = 0; (*attrs)[i]->mod_values[j] != NULL; j++);
1236 
1237 			(*attrs)[i]->mod_values =
1238 				(char **)realloc((*attrs)[i]->mod_values,
1239 						(j + 2) * sizeof (char *));
1240 			if ((*attrs)[i]->mod_values != NULL)
1241 			{
1242 				(*attrs)[i]->mod_values[j] = strdup(value);
1243 				(*attrs)[i]->mod_values[j+1] = NULL;
1244 			}
1245 			else
1246 			{
1247 				result = NSL_ERR_MEMORY;
1248 			}
1249 		}
1250 	}
1251 
1252 	return (result);
1253 } /* _addLDAPmodValue */
1254 
1255 
1256 
1257 
1258 /*
1259  * *****************************************************************************
1260  *
1261  * Function:    _modLDAPmodValue()
1262  *
1263  * Description: Add the given attribute modify operation and its value into
1264  *              the LDAPMod array. This will either be a "replace" or a
1265  *              "delete"; value = null implies a "delete".
1266  *              If this is the first entry in the array then create it.
1267  *
1268  * Parameters:
1269  * Input:       LDAPMod ***attrs  - array to update
1270  *              char *type        - attribute to modify
1271  *              char *value       - attribute value, null implies "delete"
1272  * Output:      None
1273  *
1274  * Returns:     NSL_RESULT - NSL_OK = added okay
1275  *
1276  * *****************************************************************************
1277  */
1278 
1279 static NSL_RESULT
1280 _modLDAPmodValue(LDAPMod ***attrs, char *type, char *value)
1281 
1282 {
1283 	int i = 0;
1284 	int j = 0;
1285 	NSL_RESULT result = NSL_OK;
1286 
1287 	/* ---------- */
1288 
1289 	if ((attrs != NULL) && (type != NULL))
1290 	{
1291 #ifdef DEBUG
1292 if (value != NULL)
1293 printf("_modLDAPmodValue() REPLACE type='%s', value='%s'\n", type, value);
1294 else
1295 printf("_modLDAPmodValue() DELETE type='%s'\n", type);
1296 #endif
1297 		/* search the existing LDAPMod array for the attribute */
1298 
1299 		for (i = 0; *attrs != NULL && (*attrs)[i] != NULL; i++)
1300 		{
1301 			if (strcasecmp((*attrs)[i]->mod_type, type) == 0)
1302 			{
1303 				break;
1304 			}
1305 		}
1306 
1307 		if (*attrs == NULL)
1308 		{
1309 			/* array empty so create it */
1310 
1311 			*attrs = (LDAPMod **)calloc(1, 2 * sizeof (LDAPMod *));
1312 			if (*attrs != NULL)
1313 			{
1314 				i = 0;
1315 			}
1316 			else
1317 			{
1318 				result = NSL_ERR_MEMORY;
1319 			}
1320 
1321 		}
1322 		else
1323 		if ((*attrs)[i] == NULL)
1324 		{
1325 			/* attribute not found in array so add slot for it */
1326 
1327 			*attrs = (LDAPMod **)
1328 				realloc(*attrs, (i+2) * sizeof (LDAPMod *));
1329 			if (*attrs == NULL)
1330 			{
1331 				result = NSL_ERR_MEMORY;
1332 			}
1333 		}
1334 	}
1335 	else
1336 	{
1337 		result = NSL_ERR_INTERNAL;
1338 	}
1339 
1340 	if (result == NSL_OK)
1341 	{
1342 		if ((*attrs)[i] == NULL)
1343 		{
1344 			/* We've got a new slot. Create the new mod entry */
1345 
1346 			(*attrs)[i] = (LDAPMod *) malloc(sizeof (LDAPMod));
1347 			if (((*attrs)[i] != NULL) && (value != NULL))
1348 			{
1349 				/* Do an attribute replace */
1350 
1351 				(*attrs)[i]->mod_op = LDAP_MOD_REPLACE;
1352 				(*attrs)[i]->mod_type = strdup(type);
1353 				(*attrs)[i]->mod_values = (char **)
1354 						malloc(2 * sizeof (char *));
1355 				if ((*attrs)[i]->mod_values  != NULL)
1356 				{
1357 					(*attrs)[i]->mod_values[0] =
1358 								strdup(value);
1359 					(*attrs)[i]->mod_values[1] = NULL;
1360 					(*attrs)[i+1] = NULL;
1361 				}
1362 				else
1363 				{
1364 					result = NSL_ERR_MEMORY;
1365 				}
1366 			}
1367 			else
1368 			if ((*attrs)[i] != NULL)
1369 			{
1370 				/* value is null so do an attribute delete */
1371 
1372 				(*attrs)[i]->mod_op = LDAP_MOD_DELETE;
1373 				(*attrs)[i]->mod_type = strdup(type);
1374 				(*attrs)[i]->mod_values = NULL;
1375 				(*attrs)[i+1] = NULL;
1376 			}
1377 			else
1378 			{
1379 				result = NSL_ERR_MEMORY; /* malloc failed */
1380 			}
1381 		}
1382 
1383 		else
1384 		{
1385 			/* Found an existing entry so add value to it */
1386 
1387 			if (value != NULL)
1388 			{
1389 			    /* add value to attribute's replace list */
1390 
1391 			    if ((*attrs)[i]->mod_op == LDAP_MOD_REPLACE)
1392 			    {
1393 				for (j = 0;
1394 				    (*attrs)[i]->mod_values[j] != NULL; j++);
1395 
1396 				(*attrs)[i]->mod_values =
1397 				(char **)realloc((*attrs)[i]->mod_values,
1398 						(j + 2) * sizeof (char *));
1399 				if ((*attrs)[i]->mod_values != NULL)
1400 				{
1401 					(*attrs)[i]->mod_values[j] =
1402 								strdup(value);
1403 					(*attrs)[i]->mod_values[j+1] = NULL;
1404 				}
1405 				else
1406 				{
1407 					result = NSL_ERR_MEMORY;
1408 				}
1409 			    }
1410 			    else
1411 			    {
1412 				/* Delete and replace not allowed */
1413 				result = NSL_ERR_MULTIOP;
1414 			    }
1415 			}
1416 
1417 			else
1418 			{
1419 				/*
1420 				 * attribute delete - so free any existing
1421 				 * entries in the value array
1422 				 */
1423 
1424 				(*attrs)[i]->mod_op = LDAP_MOD_DELETE;
1425 
1426 				if ((*attrs)[i]->mod_values != NULL)
1427 				{
1428 					for (j = 0;
1429 					    (*attrs)[i]->mod_values[j] != NULL;
1430 					    j++)
1431 					{
1432 					    free((*attrs)[i]->mod_values[j]);
1433 					}
1434 
1435 					free((*attrs)[i]->mod_values);
1436 					(*attrs)[i]->mod_values = NULL;
1437 				}
1438 			}
1439 		}
1440 	}
1441 
1442 	return (result);
1443 } /* _modLDAPmodValue */
1444 
1445 
1446 
1447 
1448 
1449 /*
1450  * *****************************************************************************
1451  *
1452  * Function:    _constructAddLDAPMod()
1453  *
1454  * Description: For the given attribute list construct an
1455  *              LDAPMod array for the printer object to be added. Default
1456  *              attribute values are included.
1457  *
1458  * Parameters:
1459  * Input:
1460  *              uchar_t *printerName - Name of printer to be added
1461  *              char    **attrList - user specified attribute values list
1462  * Output:      LDAPMod ***attrs  - pointer to the constructed array
1463  *
1464  * Returns:     NSL_RESULT - NSL_OK = constructed okay
1465  *
1466  * *****************************************************************************
1467  */
1468 
1469 static NSL_RESULT
1470 _constructAddLDAPMod(uchar_t *printerName, char **attrList,  LDAPMod ***attrs)
1471 
1472 {
1473 	NSL_RESULT result = NSL_ERROR;
1474 	int len = 0;
1475 	char **p = NULL;
1476 	char *value = NULL;
1477 	char *attr = NULL;
1478 
1479 	/* ---------- */
1480 
1481 	if ((printerName != NULL) &&
1482 	    ((attrList != NULL) && (attrList[0] != NULL)) && (attrs != NULL))
1483 	{
1484 		*attrs = NULL;
1485 
1486 		/*
1487 		 * setup printer object attribute values in an LDAPMod structure
1488 		 */
1489 		result = _addLDAPmodValue(attrs, ATTR_OCLASS, OCV_TOP);
1490 		if (result == NSL_OK)
1491 		{
1492 			/* Structural Objectclass */
1493 			result =
1494 			    _addLDAPmodValue(attrs, ATTR_OCLASS, OCV_PSERVICE);
1495 		}
1496 		if (result == NSL_OK)
1497 		{
1498 			result = _addLDAPmodValue(attrs,
1499 						ATTR_OCLASS, OCV_PABSTRACT);
1500 		}
1501 		if (result == NSL_OK)
1502 		{
1503 			result = _addLDAPmodValue(attrs,
1504 						ATTR_OCLASS, OCV_SUNPRT);
1505 		}
1506 		if (result == NSL_OK)
1507 		{
1508 			result = _addLDAPmodValue(attrs,
1509 					ATTR_PNAME, (char *)printerName);
1510 		}
1511 
1512 		/*
1513 		 * Now work through the user supplied attribute
1514 		 * values list and add them into the LDAPMod array
1515 		 */
1516 
1517 		for (p = attrList;
1518 			(p != NULL) && (*p != NULL) && (result == NSL_OK); p++)
1519 		{
1520 			/* get length of this key word */
1521 
1522 			for (len = 0;
1523 			    ((*p)[len] != '=') && ((*p)[len] != '\0'); len++);
1524 
1525 			if ((strlen(*p) > len+1))
1526 			{
1527 				attr = strdup(*p);
1528 				attr[len] = '\0';
1529 				value = strdup(&attr[len+1]);
1530 
1531 				/* handle specific Key Value Pairs (KVP) */
1532 
1533 				if (strcasecmp(attr, NS_KEY_BSDADDR) == 0)
1534 				{
1535 					/* use LDAP attribute name */
1536 					free(attr);
1537 					attr = strdup(ATTR_BSDADDR);
1538 				}
1539 				else
1540 				if (_attrInLDAPList(attr) == 0)
1541 				{
1542 					/*
1543 					 * Non-LDAP attribute so use LDAP
1544 					 * KVP attribute and the given KVP
1545 					 * as the value, ie.
1546 					 * sun-printer-kvp=description=printer
1547 					 */
1548 					free(attr);
1549 					attr = strdup(ATTR_KVP);
1550 					value = strdup(*p);
1551 				}
1552 
1553 				/* add it into the LDAPMod array */
1554 
1555 				result = _addLDAPmodValue(attrs, attr, value);
1556 
1557 				free(attr);
1558 				free(value);
1559 			}
1560 		} /* for */
1561 
1562 		if ((result != NSL_OK) && (*attrs != NULL))
1563 		{
1564 			(void) ldap_mods_free(*attrs, 1);
1565 			attrs = NULL;
1566 		}
1567 	}
1568 	else
1569 	{
1570 		result = NSL_ERR_INTERNAL;
1571 	}
1572 
1573 	return (result);
1574 } /* _constructAddLDAPMod */
1575 
1576 
1577 
1578 
1579 
1580 
1581 
1582 /*
1583  * *****************************************************************************
1584  *
1585  * Function:    _constructModLDAPMod()
1586  *
1587  * Description: For the given modify attribute list, construct an
1588  *              LDAPMod array for the printer object to be modified
1589  *
1590  * Parameters:
1591  * Input:       uchar_t *printerName - name of printer to be modified
1592  *              int     sunPrinter - Boolean; object is a sunPrinter
1593  *              char    **attrList - user specified attribute values list
1594  *              char    ***oldKVPList - current list of KVP values on object
1595  * Output:      LDAPMod ***attrs  - pointer to the constructed array
1596  *
1597  * Returns:     NSL_RESULT - NSL_OK = constructed okay
1598  *
1599  * *****************************************************************************
1600  */
1601 
1602 static NSL_RESULT
1603 _constructModLDAPMod(uchar_t *printerName, int sunPrinter, char **attrList,
1604 			char ***oldKVPList, LDAPMod ***attrs)
1605 
1606 {
1607 	NSL_RESULT result = NSL_OK;
1608 	int len = 0;
1609 	int kvpUpdated = 0;
1610 	int kvpExists = 0;
1611 	char **p = NULL;
1612 	char *value = NULL;
1613 	char *attr = NULL;
1614 
1615 	/* ---------- */
1616 
1617 	if ((printerName != NULL) &&
1618 	    ((attrList != NULL) && (attrList[0] != NULL)) && (attrs != NULL))
1619 	{
1620 		*attrs = NULL;
1621 
1622 		if ((oldKVPList != NULL) && (*oldKVPList != NULL))
1623 		{
1624 			kvpExists = 1;
1625 		}
1626 
1627 		if (!sunPrinter)
1628 		{
1629 			/*
1630 			 * The object was previously not a sunPrinter, so
1631 			 * add the required objectclass attribute value, and
1632 			 * ensure it has the printername attribute.
1633 			 */
1634 			result = _addLDAPmodValue(attrs,
1635 						ATTR_OCLASS, OCV_SUNPRT);
1636 			if (result == NSL_OK)
1637 			{
1638 				result = _modLDAPmodValue(attrs,
1639 					    ATTR_PNAME, (char *)printerName);
1640 			}
1641 		}
1642 
1643 		/*
1644 		 * work through the user supplied attribute
1645 		 * values list and add them into the LDAPMod array depending
1646 		 * on if they are a replace or delete attribute operation,
1647 		 * a "null value" means delete.
1648 		 */
1649 
1650 		for (p = attrList;
1651 			(p != NULL) && (*p != NULL) && (result == NSL_OK); p++)
1652 		{
1653 			/* get length of this key word */
1654 
1655 			for (len = 0;
1656 			    ((*p)[len] != '=') && ((*p)[len] != '\0'); len++);
1657 
1658 			if ((strlen(*p) > len+1))
1659 			{
1660 				attr = strdup(*p);
1661 				attr[len] = '\0';
1662 				value = strdup(&attr[len+1]);
1663 
1664 				/* handle specific Key Value Pairs (KVP) */
1665 
1666 				if ((_attrInLDAPList(attr) == 0) &&
1667 					(strcasecmp(attr, NS_KEY_BSDADDR) != 0))
1668 				{
1669 					/*
1670 					 * Non-LDAP attribute so use LDAP
1671 					 * KVP attribute and the given KVP as
1672 					 * the value, ie.
1673 					 * sun-printer-kvp=description=printer
1674 					 */
1675 					result = _modAttrKVP(*p, oldKVPList);
1676 					kvpUpdated = 1;
1677 				}
1678 
1679 				else
1680 				{
1681 					if (strcasecmp(attr, NS_KEY_BSDADDR) ==
1682 									0)
1683 					{
1684 						/*
1685 						 * use LDAP bsdaddr attribute
1686 						 * name
1687 						 */
1688 						free(attr);
1689 						attr = strdup(ATTR_BSDADDR);
1690 					}
1691 
1692 					/*
1693 					 * else
1694 					 *   use the supplied attribute name
1695 					 */
1696 
1697 					/* add it into the LDAPMod array */
1698 
1699 					result = _modLDAPmodValue(attrs,
1700 								attr, value);
1701 				}
1702 
1703 				free(attr);
1704 				free(value);
1705 			}
1706 
1707 			else
1708 			if (strlen(*p) >= 1)
1709 			{
1710 				/* handle attribute DELETE request */
1711 
1712 				attr = strdup(*p);
1713 				if (attr[len] == '=')
1714 				{
1715 					/* terminate "attribute=" */
1716 					attr[len] = '\0';
1717 				}
1718 
1719 				/* handle specific Key Value Pairs (KVP) */
1720 
1721 				if (strcasecmp(attr, NS_KEY_BSDADDR) == 0)
1722 				{
1723 					/* use LDAP bsdaddr attribute name */
1724 					result = _modLDAPmodValue(attrs,
1725 							ATTR_BSDADDR, NULL);
1726 				}
1727 				else
1728 				if (_attrInLDAPList(attr) == 0)
1729 				{
1730 					/*
1731 					 * Non-LDAP kvp, so sort items
1732 					 * in the kvp list
1733 					 */
1734 					result = _modAttrKVP(*p, oldKVPList);
1735 					kvpUpdated = 1;
1736 				}
1737 				else
1738 				{
1739 					result = _modLDAPmodValue(attrs,
1740 							attr, NULL);
1741 				}
1742 
1743 				free(attr);
1744 			}
1745 		} /* for */
1746 
1747 		if ((result == NSL_OK) && (kvpUpdated))
1748 		{
1749 			result = _attrAddKVP(attrs, *oldKVPList, kvpExists);
1750 		}
1751 
1752 		if ((result != NSL_OK) && (*attrs != NULL))
1753 		{
1754 			(void) ldap_mods_free(*attrs, 1);
1755 			*attrs = NULL;
1756 		}
1757 	}
1758 	else
1759 	{
1760 		result = NSL_ERR_INTERNAL;
1761 	}
1762 
1763 	return (result);
1764 } /* _constructModLDAPMod */
1765 
1766 
1767 
1768 
1769 
1770 
1771 /*
1772  * *****************************************************************************
1773  *
1774  * Function:    _compareURIinDNs()
1775  *
1776  * Description: For the 2 given printer object DNs compare the naming part
1777  *              part of the DN (printer-uri) to see if they are the same.
1778  *
1779  * Note:        This function only returns "compare failed" if their URI don't
1780  *              compare. Problems with the dn etc., return a good compare
1781  *              because I don't want us to create a new object for these
1782  *
1783  * Parameters:
1784  * Input:       uchar_t *dn1
1785  *              uchar_t *dn2
1786  * Output:      None
1787  *
1788  * Returns:     NSL_RESULT - NSL_OK = URIs are the same
1789  *
1790  * *****************************************************************************
1791  */
1792 
1793 static NSL_RESULT
1794 _compareURIinDNs(uchar_t *dn1, uchar_t *dn2)
1795 
1796 {
1797 	NSL_RESULT result = NSL_OK;
1798 	uchar_t *DN1 = NULL;
1799 	uchar_t *DN2 = NULL;
1800 	char *p1 = NULL;
1801 	char *p2 = NULL;
1802 
1803 	/* --------- */
1804 
1805 	if ((dn1 != NULL) && (dn2 != NULL))
1806 	{
1807 		DN1 = (uchar_t *)strdup((char *)dn1);
1808 		DN2 = (uchar_t *)strdup((char *)dn2);
1809 
1810 		/* terminate each string after the printer-uri */
1811 
1812 		p1 = strstr((char *)DN1, PCONTAINER);
1813 		/* move back to the comma */
1814 		while ((p1 != NULL) && (*p1 != ',') && (p1 >= (char *)DN1))
1815 		{
1816 			p1--;
1817 		}
1818 
1819 		p2 = strstr((char *)DN2, PCONTAINER);
1820 		/* move back to the comma */
1821 		while ((p2 != NULL) && (*p2 != ',') && (p2 >= (char *)DN2))
1822 		{
1823 			p2--;
1824 		}
1825 
1826 		if ((*p1 == ',') && (*p2 == ','))
1827 		{
1828 			*p1 = '\0';	/* re-terminate it */
1829 			*p2 = '\0';	/* re-terminate it */
1830 
1831 			/* do the compare */
1832 
1833 			/*
1834 			 * Note: SHOULD really normalise the 2 DNs before
1835 			 * doing the compare
1836 			 */
1837 #ifdef DEBUG
1838 printf("_compareURIinDNs() @1 (%s) (%s)\n", DN1, DN2);
1839 #endif
1840 			if (strcasecmp((char *)DN1, (char *)DN2) != 0)
1841 			{
1842 				result = NSL_ERROR;
1843 			}
1844 
1845 		}
1846 
1847 		free(DN1);
1848 		free(DN2);
1849 	}
1850 
1851 	return (result);
1852 } /* _compareURIinDNs */
1853 
1854 
1855 
1856 
1857 
1858 
1859 
1860 /*
1861  * *****************************************************************************
1862  *
1863  * Function:    _getThisNSDomainDN()
1864  *
1865  * Description: Get the current Name Service Domain DN
1866  *              This is extracted from the result of executing ldaplist.
1867  *
1868  * Note:        Do it this way until the NS LDAP library interface is
1869  *              made public.
1870  *
1871  * Parameters:
1872  * Input:       None
1873  * Output:      None
1874  *
1875  * Returns:     uchar_t*  - pointer to NS Domain DN (The caller should free this
1876  *                          returned memory).
1877  *
1878  * *****************************************************************************
1879  */
1880 
1881 #define	LDAPLIST_D	"/usr/bin/ldaplist -d 2>&1"
1882 #define	DNID		"dn: "
1883 
1884 static uchar_t *
1885 _getThisNSDomainDN(void)
1886 
1887 {
1888 	uchar_t *domainDN = NULL;
1889 	char *cp = NULL;
1890 	char buf[BUFSIZ] = "";
1891 
1892 	/* --------- */
1893 
1894 	if (_popen(LDAPLIST_D, buf, sizeof (buf)) == 0)
1895 	{
1896 		if ((cp = strstr(buf, DNID)) != NULL)
1897 		{
1898 			cp += strlen(DNID);  /* increment past "dn: " label */
1899 			domainDN = (uchar_t *)strdup(cp);
1900 
1901 			if ((cp = strchr((char *)domainDN, '\n')) != NULL)
1902 			{
1903 				*cp = '\0'; /* terminate it */
1904 			}
1905 		}
1906 	}
1907 
1908 	return (domainDN);
1909 } /* _getThisNSDomainDN */
1910 
1911 
1912 
1913 
1914 
1915 /*
1916  * *****************************************************************************
1917  *
1918  * Function:    _popen()
1919  *
1920  * Description: General popen function. The caller should always use a full
1921  *              path cmd.
1922  *
1923  * Parameters:
1924  * Input:       char *cmd - command line to execute
1925  *              char *buffer - ptr to buffer to put result in
1926  *              int  size - size of result buffer
1927  * Output:      None
1928  *
1929  * Returns:     int - 0 = opened okay
1930  *
1931  * *****************************************************************************
1932  */
1933 
1934 static int
1935 _popen(char *cmd, char *buffer, int size)
1936 
1937 {
1938 	int result = -1;
1939 	int rsize = 0;
1940 	FILE *fptr;
1941 	char safe_cmd[BUFSIZ];
1942 	char linebuf[BUFSIZ];
1943 
1944 	/* -------- */
1945 
1946 	if ((cmd != NULL) && (buffer != NULL) && (size != 0))
1947 	{
1948 		(void) strcpy(buffer, "");
1949 		(void) strcpy(linebuf, "");
1950 		(void) snprintf(safe_cmd, BUFSIZ, "IFS=' \t'; %s", cmd);
1951 
1952 		if ((fptr = popen(safe_cmd, "r")) != NULL)
1953 		{
1954 			while ((fgets(linebuf, BUFSIZ, fptr) != NULL) &&
1955 							(rsize  < size))
1956 			{
1957 				rsize = strlcat(buffer, linebuf, size);
1958 				if (rsize >= size)
1959 				{
1960 					/* result is too long */
1961 					(void) memset(buffer, '\0', size);
1962 				}
1963 			}
1964 
1965 			if (strlen(buffer) > 0)
1966 			{
1967 				result = 0;
1968 			}
1969 
1970 			(void) pclose(fptr);
1971 		}
1972 	}
1973 
1974 	return (result);
1975 } /* popen */
1976 
1977 
1978 /*
1979  * *****************************************************************************
1980  *
1981  * Function:    _attrInList()
1982  *
1983  * Description: For the given list check if the attribute is it
1984  *
1985  * Parameters:
1986  * Input:       char *attr   - attribute to check
1987  *              char **list  - list of attributes to check against
1988  * Output:      None
1989  *
1990  * Returns:     int - TRUE = attr found in list
1991  *
1992  * *****************************************************************************
1993  */
1994 
1995 static int
1996 _attrInList(char *attr, const char **list)
1997 
1998 {
1999 	int result = 0;
2000 	int j;
2001 
2002 	/* ------- */
2003 
2004 	if ((attr != NULL) && (list != NULL))
2005 	{
2006 		for (j = 0; (list[j] != NULL) && (result != 1); j++)
2007 		{
2008 			if (strcasecmp(list[j], attr) == 0)
2009 			{
2010 				result = 1; /* found */
2011 			}
2012 		}
2013 	}
2014 
2015 	return (result);
2016 } /* _attrInList */
2017 
2018 
2019 
2020 
2021 /*
2022  * *****************************************************************************
2023  *
2024  * Function:    _attrInLDAPList()
2025  *
2026  * Description: Checks to see if the given attribute is an LDAP printing
2027  *              attribute, ie. is either in an IPP objectclass or the
2028  *              sun printer objectclass. Note: some attributes are handled
2029  *              specifically outside this function, so are excluded from
2030  *              the lists that are checked.
2031  *
2032  * Parameters:
2033  * Input:       char *attr    - attribute to check
2034  * Output:      None
2035  *
2036  * Returns:     int - TRUE = attr found in list
2037  *
2038  * *****************************************************************************
2039  */
2040 
2041 static int
2042 _attrInLDAPList(char *attr)
2043 
2044 {
2045 	int result = 0;
2046 
2047 	/* ------- */
2048 
2049 	if (_attrInList(attr, nsl_attr_printerService))
2050 	{
2051 		result = 1;	/* in list */
2052 	}
2053 	else
2054 	if (_attrInList(attr, nsl_attr_printerIPP))
2055 	{
2056 		result = 1;	/* in list */
2057 	}
2058 	else
2059 	if (_attrInList(attr, nsl_attr_sunPrinter))
2060 	{
2061 		result = 1;	/* in list */
2062 	}
2063 
2064 	return (result);
2065 } /* _attrInLDAPList */
2066 
2067 
2068 
2069 
2070 /*
2071  * *****************************************************************************
2072  *
2073  * Function:    _getCurrentKVPValues()
2074  *
2075  * Description: For the given printer object read the current set of values
2076  *              the object has for the sun-printer-kvp (Key Value pair)
2077  *
2078  * Parameters:
2079  * Input:       LDAP *ld       - existing ldap connection descriptor
2080  *              char *objectDN - DN to search for
2081  * Output:      char ***list   - returned set of kvp values
2082  *
2083  * Result:      NSL_RESULT - NSL_OK = object exists
2084  *
2085  * *****************************************************************************
2086  */
2087 
2088 static NSL_RESULT
2089 _getCurrentKVPValues(LDAP *ld, uchar_t *objectDN, char ***list)
2090 
2091 {
2092 	NSL_RESULT result = NSL_ERR_UNKNOWN_PRINTER;
2093 	int sresult = LDAP_NO_SUCH_OBJECT;
2094 	int i = 0;
2095 	LDAPMessage *ldapMsg;
2096 	char *requiredAttrs[2] = { ATTR_KVP, NULL };
2097 	LDAPMessage *ldapEntry = NULL;
2098 	char *entryAttrib = NULL;
2099 	char **attribValues = NULL;
2100 	BerElement *berElement = NULL;
2101 
2102 	/* ---------- */
2103 
2104 	if ((list != NULL) && (ld != NULL) && (objectDN != NULL))
2105 	{
2106 		/* search for this Printer in the directory */
2107 
2108 		sresult = ldap_search_s(ld, (char *)objectDN, LDAP_SCOPE_BASE,
2109 				"(objectclass=*)", requiredAttrs, 0, &ldapMsg);
2110 		if (sresult == LDAP_SUCCESS)
2111 		{
2112 			/*
2113 			 * check that the object exists and extract its
2114 			 * KVP attribute values
2115 			 */
2116 			ldapEntry = ldap_first_entry(ld, ldapMsg);
2117 			if (ldapEntry != NULL)
2118 			{
2119 				entryAttrib = ldap_first_attribute(ld,
2120 							ldapEntry, &berElement);
2121 				if ((entryAttrib != NULL) &&
2122 				    (strcasecmp(entryAttrib, ATTR_KVP) == 0))
2123 
2124 				{
2125 #ifdef DEBUG
2126 printf("Attribute: %s, its values are:\n", entryAttrib);
2127 #endif
2128 					/*
2129 					 * add each KVP value to the list
2130 					 * that we will return
2131 					 */
2132 					attribValues = ldap_get_values(
2133 						ld, ldapEntry, entryAttrib);
2134 					for (i = 0;
2135 						attribValues[i] != NULL; i++)
2136 					{
2137 					    *list = (char **)
2138 						list_append((void **)*list,
2139 						    strdup(attribValues[i]));
2140 #ifdef DEBUG
2141 printf("\t%s\n", attribValues[i]);
2142 #endif
2143 					}
2144 					(void) ldap_value_free(attribValues);
2145 				}
2146 
2147 				if ((entryAttrib != NULL) &&
2148 				    (berElement != NULL))
2149 				{
2150 					ber_free(berElement, 0);
2151 				}
2152 
2153 
2154 				/* object found */
2155 				result = NSL_OK;
2156 			}
2157 
2158 			(void) ldap_msgfree(ldapMsg);
2159 		}
2160 	}
2161 
2162 	else
2163 	{
2164 		result = NSL_ERR_INTERNAL;
2165 	}
2166 
2167 	return (result);
2168 } /* _getCurrentKVPValues */
2169 
2170 
2171 
2172 /*
2173  * *****************************************************************************
2174  *
2175  * Function:    _freeList()
2176  *
2177  * Description: Free the list created by list_append() where the items in
2178  *              the list have been strdup'ed.
2179  *
2180  * Parameters:
2181  * Input:       char ***list   - returned set of kvp values
2182  *
2183  * Result:      void
2184  *
2185  * *****************************************************************************
2186  */
2187 
2188 static void
2189 _freeList(char ***list)
2190 
2191 {
2192 	int i = 0;
2193 
2194 	/* ------ */
2195 
2196 	if (list != NULL)
2197 	{
2198 		if (*list != NULL)
2199 		{
2200 			for (i = 0; (*list)[i] != NULL; i++)
2201 			{
2202 				free((*list)[i]);
2203 			}
2204 			free(*list);
2205 		}
2206 
2207 		*list = NULL;
2208 	}
2209 } /* _freeList */
2210 
2211 
2212 
2213 /*
2214  * *****************************************************************************
2215  *
2216  * Function:    _modAttrKVP()
2217  *
2218  * Description: Sort out the KVP attribute value list, such that this new
2219  *              value takes precidence over any existing value in the list.
2220  *              The current list is updated to remove this key, and the new
2221  *              key "value" is added to the list, eg. for
2222  *                  value: bbb=ddddd
2223  *                  and kvpList:
2224  *                         aaa=yyyy
2225  *                         bbb=zzzz
2226  *                         ccc=xxxx
2227  *                  the resulting kvpList is:
2228  *                         aaa=yyyy
2229  *                         ccc=xxxx
2230  *                         bbb=ddddd
2231  *
2232  * Note:        When all new values have been handled the function _attrAddKVP()
2233  *              must be called to add the "new list" values into the
2234  *              LDAPMod array.
2235  *
2236  * Parameters:
2237  * Input:       char *value       - Key Value Pair to process,
2238  *                                  eg. aaaaa=hhhhh, where aaaaa is the key
2239  *              char ***kvpList   - list of current KVP values
2240  * Output:      char ***kvpList   - updated list of KVP values
2241  *
2242  * Returns:     NSL_RESULT - NSL_OK = done okay
2243  *
2244  * *****************************************************************************
2245  */
2246 
2247 static NSL_RESULT
2248 _modAttrKVP(char *value, char ***kvpList)
2249 
2250 {
2251 	NSL_RESULT result = NSL_ERR_INTERNAL;
2252 	int i = 0;
2253 	int inList = 0;
2254 	int keyDelete = 0;
2255 	char *key = NULL;
2256 	char **p = NULL;
2257 	char **newList = NULL;
2258 
2259 	/* ------- */
2260 
2261 	if ((value != NULL) && (kvpList != NULL))
2262 	{
2263 		result = NSL_OK;
2264 
2265 		/* extract "key" from value */
2266 
2267 		key = strdup(value);
2268 
2269 		for (i = 0; ((key)[i] != '=') && ((key)[i] != '\0'); i++);
2270 		key[i] = '\0'; /* terminate the key */
2271 
2272 		/* Is this a request to delete a "key" value */
2273 
2274 		if ((value[i] == '\0') || (value[i+1] == '\0'))
2275 		{
2276 			/* this is a request to delete the key */
2277 			keyDelete = 1;
2278 		}
2279 
2280 		if ((*kvpList != NULL) && (**kvpList != NULL))
2281 		{
2282 			/*
2283 			 * for each item in the list remove it if the keys match
2284 			 */
2285 			for (p = *kvpList; *p != NULL; p++)
2286 			{
2287 				for (i = 0;
2288 				    ((*p)[i] != '=') && ((*p)[i] != '\0'); i++);
2289 
2290 				if ((strlen(key) == i) &&
2291 					(strncasecmp(*p, key, i) == 0))
2292 				{
2293 					inList = 1;
2294 				}
2295 				else
2296 				{
2297 					/* no match so add value to new list */
2298 					newList = (char **)list_append(
2299 							(void **)newList,
2300 							strdup(*p));
2301 				}
2302 			}
2303 		}
2304 
2305 		/*
2306 		 * if it was not a DELETE request add the new key value into
2307 		 * the newList, otherwise we have already removed the key
2308 		 */
2309 
2310 		if (!keyDelete)
2311 		{
2312 			newList = (char **)list_append((void **)newList,
2313 							strdup(value));
2314 		}
2315 
2316 		if ((newList != NULL) || (inList))
2317 		{
2318 			/* replace old list with the newList */
2319 			_freeList(kvpList);
2320 			*kvpList = newList;
2321 		}
2322 
2323 		free(key);
2324 	}
2325 
2326 	return (result);
2327 } /* modAttrKVP */
2328 
2329 
2330 
2331 
2332 /*
2333  * *****************************************************************************
2334  *
2335  * Function:    _attrAddKVP()
2336  *
2337  * Description: Process KVP items in the kvpList adding them to the
2338  *              LDAPMod modify array. If the list is empty but there were
2339  *              previously LDAP KVP values delete them.
2340  *
2341  * Note:        This function should only be called when all the new KVP
2342  *              items have been processed by _modAttrKVP()
2343  *
2344  * Parameters:
2345  * Input:       LDAPMod ***attrs - array to update
2346  *              char **kvpList   - list KVP values
2347  *              int  kvpExists   - object currently has LDAP KVP values
2348  * Output:      None
2349  *
2350  * Returns:     NSL_RESULT - NSL_OK = done okay
2351  *
2352  * *****************************************************************************
2353  */
2354 
2355 static NSL_RESULT
2356 _attrAddKVP(LDAPMod ***attrs, char **kvpList, int kvpExists)
2357 
2358 {
2359 	NSL_RESULT result = NSL_OK;
2360 
2361 	/* ------- */
2362 
2363 	if (attrs != NULL)
2364 	{
2365 		if (kvpList != NULL)
2366 		{
2367 			while ((kvpList != NULL) && (*kvpList != NULL))
2368 			{
2369 				/* add item to LDAPMod array */
2370 
2371 				result =
2372 				    _modLDAPmodValue(attrs, ATTR_KVP, *kvpList);
2373 
2374 				kvpList++;
2375 			}
2376 		}
2377 		else
2378 		if (kvpExists)
2379 		{
2380 			/*
2381 			 * We now have no LDAP KVP values but there were
2382 			 * some previously, so delete them
2383 			 */
2384 			result = _modLDAPmodValue(attrs, ATTR_KVP, NULL);
2385 		}
2386 	}
2387 
2388 	else
2389 	{
2390 		result = NSL_ERR_INTERNAL;
2391 	}
2392 
2393 	return (result);
2394 } /* _attrAddKVP */
2395 
2396 
2397 
2398 
2399 /*
2400  * *****************************************************************************
2401  *
2402  * Function:    _manageReferralCredentials()
2403  *
2404  * Description: This function is called if a referral request is returned by
2405  *              the origonal LDAP server during the ldap update request call,
2406  *              eg. ldap_add_s(), ldap_modify_s() or ldap_delete_s().
2407  * Parameters:
2408  * Input:       LDAP *ld      - LDAP descriptor
2409  *              int freeit    - 0 = first call to get details
2410  *                            - 1 = second call to free details
2411  *                            - -1 = initial store of authentication details
2412  * Input/Output: char **dn    - returns DN to bind to on master
2413  *               char **credp - returns password for DN
2414  *               int *methodp - returns authentication type, eg. simple
2415  *
2416  * Returns:     int - 0 = okay
2417  *
2418  * *****************************************************************************
2419  */
2420 static int _manageReferralCredentials(LDAP *ld, char **dn, char **credp,
2421 					int *methodp, int freeit)
2422 
2423 {
2424 	int result = 0;
2425 	static char *sDN = NULL;
2426 	static char *sPasswd = NULL;
2427 	static int  sMethod = LDAP_AUTH_SIMPLE;
2428 
2429 	/* -------- */
2430 
2431 	if (freeit == 1)
2432 	{
2433 		/* second call - free memory */
2434 
2435 		if ((dn != NULL) && (*dn != NULL))
2436 		{
2437 			free(*dn);
2438 		}
2439 
2440 		if ((credp != NULL) && (*credp != NULL))
2441 		{
2442 			free(*credp);
2443 		}
2444 	}
2445 
2446 	else
2447 	if ((ld != NULL) &&
2448 	    (dn != NULL) && (credp != NULL) && (methodp != NULL))
2449 	{
2450 		if ((freeit == 0) && (sDN != NULL) && (sPasswd != NULL))
2451 		{
2452 			/* first call - get the saved bind credentials */
2453 
2454 			*dn = strdup(sDN);
2455 			*credp = strdup(sPasswd);
2456 			*methodp = sMethod;
2457 		}
2458 		else
2459 		if (freeit == -1)
2460 		{
2461 			/* initial call - save the saved bind credentials */
2462 
2463 			sDN = *dn;
2464 			sPasswd = *credp;
2465 			sMethod = *methodp;
2466 		}
2467 		else
2468 		{
2469 			result = 1;	/* error */
2470 		}
2471 	}
2472 	else
2473 	{
2474 		result = 1;	/* error */
2475 	}
2476 
2477 	return (result);
2478 } /* _manageReferralCredentials */
2479