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