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