diff options
Diffstat (limited to 'usr/src/lib/print/libprint/common/nss_ldap.c')
-rw-r--r-- | usr/src/lib/print/libprint/common/nss_ldap.c | 2478 |
1 files changed, 2478 insertions, 0 deletions
diff --git a/usr/src/lib/print/libprint/common/nss_ldap.c b/usr/src/lib/print/libprint/common/nss_ldap.c new file mode 100644 index 0000000000..887babc740 --- /dev/null +++ b/usr/src/lib/print/libprint/common/nss_ldap.c @@ -0,0 +1,2478 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <string.h> +#include <stdarg.h> +#include <fcntl.h> +#include <syslog.h> +#include <errno.h> +#include <pwd.h> +#include <libintl.h> +#include <netdb.h> /* for rcmd() */ + +#include <ns.h> +#include <list.h> +#include <misc.h> + +#define LDAP_REFERRALS +#include <lber.h> +#include <ldap.h> +#include <sys/systeminfo.h> + + +/* + * This modules contains the code required to manipulate printer objects in + * a LDAP directory for the Naming Service (NS) switch. + * It can "add", "modify" and "delete" the objects on the given ldap server + * and in the given NS domain DN, eg. "dc=mkg,dc=sun,dc=com". + * Note: printers known to the naming service are contained in the RDN + * "ou=printers" under the NS domain DN + */ + +#define PCONTAINER "ou=printers" + +/* attribute keywords */ +#define ATTR_DN "dn" +#define ATTR_OCLASS "objectClass" +#define ATTR_URI "printer-uri" +#define ATTR_PNAME "printer-name" +#define ATTR_XRISUP "printer-xri-supported" +#define ATTR_BSDADDR "sun-printer-bsdaddr" +#define ATTR_KVP "sun-printer-kvp" + +/* objectClass values */ +#define OCV_TOP "top" +#define OCV_PSERVICE "printerService" +#define OCV_SUNPRT "sunPrinter" +#define OCV_PABSTRACT "printerAbstract" + +/* xri-supported attribute value */ +#define AV_UNKNOWN "unknown" + + +/* + * LDAP objectclass atributes that the user can explicity change + */ + +static const char *nsl_attr_printerService[] = { + "printer-uri", + "printer-xri-supported", + /* Not allowed "printer-name", */ + "printer-natural-language-configured", + "printer-location", + "printer-info", + "printer-more-info", + "printer-make-and-model", + "printer-charset-configured", + "printer-charset-supported", + "printer-generated-natural-language-supported", + "printer-document-format-supported", + "printer-color-supported", + "printer-compression-supported", + "printer-pages-per-minute", + "printer-pages-per-minute-color", + "printer-finishings-supported", + "printer-number-up-supported", + "printer-sides-supported", + "printer-media-supported", + "printer-media-local-supported", + "printer-resolution-supported", + "printer-print-quality-supported", + "printer-job-priority-supported", + "printer-copies-supported", + "printer-job-k-octets-supported", + "printer-current-operator", + "printer-service-person", + "printer-delivery-orientation-supported", + "printer-stacking-order-supported", + "printer-output-features-supported", + (char *)NULL +}; + + +static const char *nsl_attr_printerIPP[] = { + "printer-ipp-versions-supported", + "printer-multiple-document-jobs-supported", + (char *)NULL +}; + +static const char *nsl_attr_sunPrinter[] = { + /* Not allowed "sun-printer-bsdaddr", */ + /* Not allowed "sun-printer-kvp", */ + (char *)NULL +}; + + +/* + * List of LDAP attributes that user is not allowed to explicitly change + */ +static const char *nsl_attr_notAllowed[] = { + ATTR_DN, + ATTR_OCLASS, /* objectclass */ + ATTR_PNAME, /* printer-name */ + ATTR_BSDADDR, + ATTR_KVP, + (char *)NULL +}; + + +static NSL_RESULT _connectToLDAP(ns_cred_t *cred, LDAP **ld); +static uchar_t *_constructPrinterDN(uchar_t *printerName, + uchar_t *domainDN, char **attrList); +static NSL_RESULT _checkPrinterExists(LDAP *ld, uchar_t *printerName, + uchar_t *domainDN, uchar_t **printerDN); +static NSL_RESULT _checkPrinterDNExists(LDAP *ld, uchar_t *objectDN); +static NSL_RESULT _checkSunPrinter(LDAP *ld, uchar_t *printerDN); +static NSL_RESULT _addNewPrinterObject(LDAP *ld, uchar_t *printerName, + uchar_t *domainDN, char **attrList); +static NSL_RESULT _modifyPrinterObject(LDAP *ld, uchar_t *printerDN, + uchar_t *printerName, uchar_t *domainDN, char **attrList); +static NSL_RESULT _checkAttributes(char **list); +static NSL_RESULT _addLDAPmodValue(LDAPMod ***attrs, char *type, char *value); +static NSL_RESULT _modLDAPmodValue(LDAPMod ***attrs, char *type, char *value); +static NSL_RESULT _constructAddLDAPMod(uchar_t *printerName, + char **attrList, LDAPMod ***attrs); +static NSL_RESULT _constructModLDAPMod(uchar_t *printerName, int sunPrinter, + char **attrList, char ***oldKVPList, LDAPMod ***attrs); +static NSL_RESULT _compareURIinDNs(uchar_t *dn1, uchar_t *dn2); +static uchar_t *_getThisNSDomainDN(void); +static int _popen(char *cmd, char *results, int size); +static int _attrInList(char *attr, const char **list); +static int _attrInLDAPList(char *attr); +static NSL_RESULT _getCurrentKVPValues(LDAP *ld, + uchar_t *objectDN, char ***list); +static void _freeList(char ***list); +static NSL_RESULT _modAttrKVP(char *value, char ***kvpList); +static NSL_RESULT _attrAddKVP(LDAPMod ***attrs, char **kvpList, int kvpExists); +static int _manageReferralCredentials(LDAP *ld, char **dn, char **credp, + int *methodp, int freeit); + +/* + * ***************************************************************************** + * + * Function: ldap_put_printer() + * + * Description: Action the request to change a printer object in the LDAP + * directory DIT. The object is either added, modified or deleted + * depending on the request's attribute list. A null list indicates + * the request is a delete. + * The object's DN is constructed from the supplied domain DN and + * a check is done to see if the object exists already, if it + * doesn't exist then this is a request to add a new object + * If a URI is given in the attribute list and it is different to + * the existing printing object's DN then the request will be + * rejected. + * + * + * Parameters: + * Input: const ns_printer_t *printer + * - this structure contains the following : + * char *printerName - name of the printer + * ns_cred_t *cred - structure containing the ldap host and + * port, user, password and NS domain DN for the + * directory server to be updated. + * char **attrList - pointer to a list of attribute key values + * for the printer object. If the object does + * not already exist then this list contains the + * values for the new object, otherwise this list + * is a list of attributes to modify. For modify + * a null attribute value is a attribute delete + * request. A NULL ptr = delete the object. + * Output: None + * + * Returns: int - 0 = request actioned okay + * !0 = error - see NSL_RESULT codes + * + * ***************************************************************************** + */ + +int +ldap_put_printer(const ns_printer_t *printer) + +{ + NSL_RESULT result = NSL_OK; + NSL_RESULT printerExists = NSL_ERR_UNKNOWN_PRINTER; + LDAP *ld = NULL; + uchar_t *printerDN = NULL; + uchar_t *domainDN = NULL; + char *printerName = NULL; + ns_cred_t *cred = NULL; + char **attrList = NULL; + + /* -------- */ + + /* + * Note: the "attributes" list should be null for ldap as the attribute + * values are passed in the nsdata field + */ + + if ((printer != NULL) && + (printer->attributes == NULL) && (printer->name != NULL)) + { + /* extract required pointer values from structure */ + + printerName = printer->name; + cred = printer->cred; + if (printer->nsdata != NULL) + { + attrList = ((NS_LDAPDATA *)(printer->nsdata))->attrList; + } + + /* connect and bind to the ldap directory server */ + + result = _connectToLDAP(cred, &ld); + if ((result == NSL_OK) && (ld != NULL)) + { + /* + * check if the NS domain DN was given, if not use the + * current NS domain + */ + + if (cred->domainDN != NULL) + { + domainDN = (uchar_t *) + strdup((char *)cred->domainDN); + } + else + { + /* get DN of current domain */ + domainDN = _getThisNSDomainDN(); + } + + printerExists = + _checkPrinterExists(ld, (uchar_t *)printerName, + domainDN, &printerDN); + if (printerExists != LDAP_SUCCESS) + { + /* + * could not find the printer by printer-name, + * but there could be a non sunPrinter object + * so if the printer-uri was given check if + * an object for that exists + */ + printerDN = + _constructPrinterDN(NULL, + domainDN, attrList); + if (printerDN != NULL) + { + printerExists = _checkPrinterDNExists( + ld, printerDN); + } + } +#ifdef DEBUG +if (printerExists == NSL_OK) +{ +printf("DN found = '%s' for '%s'\n", printerDN, printerName); +} +#endif + + if (attrList == NULL) + { + /* + * a null list indicates that this is a DELETE + * object request, so if object exists delete + * it, otherwise report an error. + */ + if (printerExists == LDAP_SUCCESS) + { + result = ldap_delete_s(ld, + (char *)printerDN); + if (result != LDAP_SUCCESS) + { + result = NSL_ERR_DEL_FAILED; +#ifdef DEBUG +ldap_perror(ld, "ldap_delete_s failed"); +#endif + } + } + else + { + result = NSL_ERR_UNKNOWN_PRINTER; + } + } + else + { + /* + * if object exists then this is a + * modify request otherwise is is an add request + */ + + if (printerExists == LDAP_SUCCESS) + { + /* + * Modify the printer object to + * give it the new attribute values + * specified by the user + */ + result = + _modifyPrinterObject(ld, printerDN, + (uchar_t *)printerName, + domainDN, attrList); + } + else + { + /* + * add new printer object into the + * ldap directory with the user + * specified attribute values + */ + result = + _addNewPrinterObject(ld, + (uchar_t *)printerName, + domainDN, attrList); + } + } + + if (printerDN != NULL) + { + free(printerDN); + } + if (domainDN != NULL) + { + free(domainDN); + } + + /* disconnect from LDAP server */ + + (void) ldap_unbind(ld); + } + } + + else + { + /* no printerName given */ + result = NSL_ERR_INTERNAL; + } + + return ((int)result); +} /* ldap_put_printer */ + + + + +/* + * ***************************************************************************** + * + * Function: _connectToLDAP() + * + * Description: Setup the connection and bind to the LDAP directory server. + * The function returns the ldap connection descriptor + * + * Note: Currently the native ldap functions do not support secure + * passwords, when this is supported this function will require + * updating to allow the type passed in cred->passwdType to + * be used with the ldap_simple_bind() + * + * Parameters: + * Input: ns_cred_t *cred - structure containing the credentials (host, + * port, user and password) required to bind + * to the directory server to be updated. + * char *printerName - printer name used only for error messages + * Output: LDAP** - ldap connection descriptor pointer. NULL = failed + * + * Returns: NSL_RESULT - NSL_OK = connected okay + * + * ***************************************************************************** + */ + +static NSL_RESULT +_connectToLDAP(ns_cred_t *cred, LDAP **ld) + +{ + NSL_RESULT result = NSL_OK; + int lresult = 0; + int ldapPort = LDAP_PORT; /* default LDAP port number */ + int protoVersion = LDAP_VERSION3; + int derefOption = LDAP_DEREF_NEVER; + int referrals = 1; + char hostname[MAXHOSTNAMELEN]; + int tmpMethod = LDAP_AUTH_SIMPLE; /* temp - until its passed in */ + + /* -------- */ + + if ((ld == NULL) || (cred == NULL) || + ((cred->passwd == NULL) || (cred->binddn == NULL))) + { + result = NSL_ERR_CREDENTIALS; + } + + else + { + *ld = NULL; + + /* if host was not given then bind to local host */ + + if (cred->host != NULL) + { + (void) strlcpy(hostname, cred->host, sizeof (hostname)); + } + else + { + (void) sysinfo(SI_HOSTNAME, + hostname, sizeof (hostname)); + } + + /* initialise the connection to the ldap server */ + + if (cred->port != 0) + { + ldapPort = cred->port; + } + *ld = ldap_init(hostname, ldapPort); + if (*ld == NULL) + { + /* connection setup failed */ + result = NSL_ERR_CONNECT; +#ifdef DEBUG +(void) perror("ldap_init"); +#endif + } + else + { + /* set ldap options */ + + (void) ldap_set_option(*ld, LDAP_OPT_DEREF, + &derefOption); + (void) ldap_set_option(*ld, LDAP_OPT_PROTOCOL_VERSION, + &protoVersion); + (void) ldap_set_option(*ld, LDAP_OPT_REFERRALS, + &referrals); + + /* bind to the user DN in the directory */ + + /* cred->passwdType is currently not supported */ + + lresult = ldap_simple_bind_s(*ld, + cred->binddn, cred->passwd); + + /* + * before doing anything else, set up the function to + * call to get authentication details if the + * ldap update function calls (eg. ldap_add_s()) get a + * "referral" (to another ldap server) from the + * original ldap server, eg. if we are trying to do + * a update on a LDAP replica server. + */ + (void) _manageReferralCredentials(*ld, + &(cred->binddn), &(cred->passwd), + &tmpMethod, -1); + ldap_set_rebind_proc(*ld, + (LDAP_REBINDPROC_CALLBACK *) + _manageReferralCredentials, NULL); + + if (lresult != LDAP_SUCCESS) + { + result = NSL_ERR_BIND; + *ld = NULL; +#ifdef DEBUG +(void) ldap_perror(*ld, "ldap_simple_bind_s"); +#endif + } + } + } + + return (result); +} /* _connectToLDAP */ + + + + + +/* + * ***************************************************************************** + * + * Function: _constructPrinterDN() + * + * Description: Construct the DN for the printer object from its name and NS + * domain DN. If the printer-uri is given in the attrList then + * that is used instead of the printerName. + * + * Parameters: + * Input: uchar_t *printerName + * uchar_t *domainDN + * char **attrList - this list is searched for printer-uri + * Output: None + * + * Returns: uchar_t* - pointer to the DN, this memory is malloced so + * must be freed using free() when finished with. + * + * ***************************************************************************** + */ + +static uchar_t * +_constructPrinterDN(uchar_t *printerName, uchar_t *domainDN, char **attrList) + +{ + uchar_t *dn = NULL; + uchar_t *uri = NULL; + char **p = NULL; + int len = 0; + + /* ------- */ + + /* first search for printer-uri in the attribute list */ + + for (p = attrList; (p != NULL) && (*p != NULL) && (uri == NULL); p++) + { + /* get length of this key word */ + + for (len = 0; ((*p)[len] != '=') && ((*p)[len] != '\0'); len++); + + if ((strncasecmp(*p, ATTR_URI, len) == 0) && + (strlen(*p) > len+1)) + { + uri = (uchar_t *)&((*p)[len+1]); + } + } + + + if (domainDN != NULL) { + size_t size; + + /* malloc memory for the DN and then construct it */ + + if ((uri == NULL) && (printerName != NULL)) + { + /* use the printerName for the RDN */ + + size = strlen(ATTR_URI) + + strlen((char *)printerName) + + strlen((char *)domainDN) + + strlen(PCONTAINER) + + 10; /* plus a few extra */ + + if ((dn = malloc(size)) != NULL) + (void) snprintf((char *)dn, size, "%s=%s,%s,%s", + ATTR_URI, printerName, PCONTAINER, domainDN); + } + else + if (uri != NULL) + { + /* use the URI for the RDN */ + + size = strlen(ATTR_URI) + + strlen((char *)uri) + + strlen((char *)domainDN) + + strlen(PCONTAINER) + + 10; /* plus a few extra */ + + if ((dn = malloc(size)) != NULL) + (void) snprintf((char *)dn, size, "%s=%s,%s,%s", + ATTR_URI, uri, PCONTAINER, domainDN); + } + + /* + * else + * { + * printName not given so return null + * } + */ + + } + + return (dn); /* caller must free this memory */ +} /* _constructPrinterDN */ + + + +/* + * ***************************************************************************** + * + * Function: _checkPrinterExists() + * + * Description: Check that the printer object for the printerName exists in the + * directory DIT and then extract the object's DN + * The function uses an exiting ldap connection and does a + * search for the printerName in the supplied domain DN. + * + * Parameters: + * Input: LDAP *ld - existing ldap connection descriptor + * uchar_t *printerName - printer name + * uchar_t *domainDN - DN of domain to search in + * Output: uchar_t **printerDN - DN of the printer - the caller should + * free this memory using free() + * + * Result: NSL_RESULT - NSL_OK = object exists + * + * ***************************************************************************** + */ + +static NSL_RESULT +_checkPrinterExists(LDAP *ld, uchar_t *printerName, uchar_t *domainDN, + uchar_t **printerDN) + +{ + NSL_RESULT result = NSL_ERR_UNKNOWN_PRINTER; + int sresult = LDAP_NO_SUCH_OBJECT; + LDAPMessage *ldapMsg = NULL; + char *requiredAttrs[2] = { ATTR_PNAME, NULL }; + LDAPMessage *ldapEntry = NULL; + uchar_t *filter = NULL; + uchar_t *baseDN = NULL; + + /* ---------- */ + + if ((printerName != NULL) && (domainDN != NULL) && (printerDN != NULL)) + { + size_t size; + + if (printerDN != NULL) + { + *printerDN = NULL; + } + + /* search for this Printer in the directory */ + + size = (3 + strlen((char *)printerName) + strlen(ATTR_PNAME) + + 2); + + if ((filter = malloc(size)) != NULL) + (void) snprintf((char *)filter, size, "(%s=%s)", + ATTR_PNAME, (char *)printerName); + + size = (strlen((char *)domainDN) + strlen(PCONTAINER) + 5); + + if ((baseDN = malloc(size)) != NULL) + (void) snprintf((char *)baseDN, size, "%s,%s", + PCONTAINER, (char *)domainDN); + + sresult = ldap_search_s(ld, (char *)baseDN, LDAP_SCOPE_SUBTREE, + (char *)filter, requiredAttrs, 0, &ldapMsg); + if (sresult == LDAP_SUCCESS) + { + /* check that the object exists and extract its DN */ + + ldapEntry = ldap_first_entry(ld, ldapMsg); + if (ldapEntry != NULL) + { + /* object found - there should only be one */ + result = NSL_OK; + + if (printerDN != NULL) + { + *printerDN = (uchar_t *) + ldap_get_dn(ld, ldapEntry); + } + } + + (void) ldap_msgfree(ldapMsg); + } + } + + else + { + result = NSL_ERR_INTERNAL; + } + + return (result); +} /* _checkPrinterExists */ + + + + +/* + * ***************************************************************************** + * + * Function: _checkPrinterDNExists() + * + * Description: Check that the printer object for the DN exists in the + * directory DIT. + * The function uses an exiting ldap connection and does a + * search for the DN supplied. + * + * Parameters: LDAP *ld - existing ldap connection descriptor + * char *objectDN - DN to search for + * + * Result: NSL_RESULT - NSL_OK = object exists + * + * ***************************************************************************** + */ + +static NSL_RESULT +_checkPrinterDNExists(LDAP *ld, uchar_t *objectDN) + +{ + NSL_RESULT result = NSL_ERR_UNKNOWN_PRINTER; + int sresult = LDAP_NO_SUCH_OBJECT; + LDAPMessage *ldapMsg; + char *requiredAttrs[2] = { ATTR_PNAME, NULL }; + LDAPMessage *ldapEntry; + + /* ---------- */ + + if ((ld != NULL) && (objectDN != NULL)) + { + /* search for this Printer in the directory */ + + sresult = ldap_search_s(ld, (char *)objectDN, LDAP_SCOPE_BASE, + "(objectclass=*)", requiredAttrs, 0, &ldapMsg); + if (sresult == LDAP_SUCCESS) + { + /* check that the object exists */ + ldapEntry = ldap_first_entry(ld, ldapMsg); + if (ldapEntry != NULL) + { + /* object found */ + result = NSL_OK; + } + + (void) ldap_msgfree(ldapMsg); + } + } + + else + { + result = NSL_ERR_INTERNAL; + } + + return (result); +} /* _checkPrinterDNExists */ + + + + + +/* + * ***************************************************************************** + * + * Function: _checkSunPrinter() + * + * Description: Check that the printer object for the printerDN is a sunPrinter + * ie. it has the required objectclass attribute value. + * + * Parameters: + * Input: LDAP *ld - existing ldap connection descriptor + * Output: uchar_t *printerDN - DN of the printer + * + * Result: NSL_RESULT - NSL_OK = object exists and is a sunPrinter + * + * ***************************************************************************** + */ + +static NSL_RESULT +_checkSunPrinter(LDAP *ld, uchar_t *printerDN) + +{ + NSL_RESULT result = NSL_ERR_UNKNOWN_PRINTER; + int sresult = LDAP_NO_SUCH_OBJECT; + char *requiredAttrs[2] = { ATTR_PNAME, NULL }; + LDAPMessage *ldapMsg = NULL; + LDAPMessage *ldapEntry = NULL; + char *filter = NULL; + + /* ---------- */ + + if ((ld != NULL) && (printerDN != NULL)) + { + size_t size; + + /* search for this Printer in the directory */ + + size = (3 + strlen(OCV_SUNPRT) + strlen(ATTR_OCLASS) + 2); + if ((filter = malloc(size)) != NULL) + (void) snprintf(filter, size, "(%s=%s)", + ATTR_OCLASS, OCV_SUNPRT); + + sresult = ldap_search_s(ld, (char *)printerDN, + LDAP_SCOPE_SUBTREE, filter, + requiredAttrs, 0, &ldapMsg); + if (sresult == LDAP_SUCCESS) + { + /* check that the printer object exists */ + + ldapEntry = ldap_first_entry(ld, ldapMsg); + if (ldapEntry != NULL) + { + /* object is a sunPrinter */ + result = NSL_OK; + } + + (void) ldap_msgfree(ldapMsg); + } + } + + else + { + result = NSL_ERR_INTERNAL; + } + + return (result); +} /* _checkSunPrinter */ + + + + + +/* + * ***************************************************************************** + * + * Function: _addNewPrinterObject() + * + * Description: For the given printerName add a printer object into the + * LDAP directory NS domain. The object is created with the + * supplied attribute values. Note: if the printer's uri is + * given that is used as the RDN otherwise the printer's + * name is used as the RDN + * + * Parameters: + * Input: LDAP *ld - existing ldap connection descriptor + * uchar_t *printerName - Name of printer to be added + * uchar_t *domainDN - DN of the domain to add the printer + * char **attrList - user specified attribute values list + * Output: None + * + * Returns: NSL_RESULT - NSL_OK = request actioned okay + * !NSL_OK = error + * + * ***************************************************************************** + */ + +static NSL_RESULT +_addNewPrinterObject(LDAP *ld, uchar_t *printerName, + uchar_t *domainDN, char **attrList) + +{ + NSL_RESULT result = NSL_ERR_ADD_FAILED; + int lresult = 0; + uchar_t *printerDN = NULL; + LDAPMod **attrs = NULL; + + /* ---------- */ + + if ((ld != NULL) && (printerName != NULL) && (domainDN != NULL) && + (attrList != NULL) && (attrList[0] != NULL)) + { + result = _checkAttributes(attrList); + + if (result == NSL_OK) + { + /* + * construct a DN for the printer from the + * printerName and printer-uri if given. + */ + printerDN = _constructPrinterDN(printerName, + domainDN, attrList); + if (printerDN != NULL) + { + /* + * setup attribute values in an LDAPMod + * structure and then add the object + */ + result = _constructAddLDAPMod(printerName, + attrList, &attrs); + if (result == NSL_OK) + { + lresult = ldap_add_s(ld, + (char *)printerDN, attrs); + if (lresult == LDAP_SUCCESS) + { + result = NSL_OK; + } + else + { + result = NSL_ERR_ADD_FAILED; +#ifdef DEBUG +(void) ldap_perror(ld, "ldap_add_s"); +#endif + } + + (void) ldap_mods_free(attrs, 1); + } + free(printerDN); + } + + else + { + result = NSL_ERR_INTERNAL; + } + } + } + + else + { + result = NSL_ERR_INTERNAL; + } + + return (result); +} /* _addNewPrinterObject */ + + + + + + +/* + * ***************************************************************************** + * + * Function: _modifyPrinterObject() + * + * Description: Modify the given LDAP printer object to set the new attributes + * in the attribute list. If the printer's URI (specified in the + * attrList) changes the URI of the object the request is rejected. + * + * Parameters: + * Input: LDAP *ld - existing ldap connection descriptor + * uchar_t *printerDN - DN of printer object to modify + * uchar_t *printerName - Name of printer to be modified + * uchar_t *domainDN - DN of the domain the printer is in + * char **attrList - user specified attribute values list + * Output: None + * + * Returns: NSL_RESULT - NSL_OK = object modified okay + * + * ***************************************************************************** + */ + +static NSL_RESULT +_modifyPrinterObject(LDAP *ld, uchar_t *printerDN, + uchar_t *printerName, uchar_t *domainDN, char **attrList) + +{ + NSL_RESULT result = NSL_ERR_INTERNAL; + int lresult = 0; + int sunPrinter = 0; + uchar_t *uriDN = NULL; + LDAPMod **attrs = NULL; + char **kvpList = NULL; + + /* ---------- */ + + if ((ld != NULL) && (printerDN != NULL) && (printerName != NULL) && + (domainDN != NULL) && (attrList != NULL) && (attrList[0] != NULL)) + { + result = _checkAttributes(attrList); + + if (result == NSL_OK) + { + /* + * The user may have requested that the printer object + * be given a new URI RDN, so construct a DN for the + * printer from the printerName or the printer-uri (if + * given). + */ + uriDN = _constructPrinterDN(NULL, domainDN, attrList); + + /* + * compare the 2 DNs to see if the URI has changed, + * if uriDN is null then the DN hasn't changed + */ + if ((uriDN == NULL) || ((uriDN != NULL) && + (_compareURIinDNs(printerDN, uriDN) == NSL_OK))) + { + /* + * setup the modify object LDAPMod + * structure and then do the modify + */ + + if (_checkSunPrinter(ld, printerDN) == NSL_OK) + { + sunPrinter = 1; + } + + (void) _getCurrentKVPValues(ld, + printerDN, &kvpList); + + result = _constructModLDAPMod(printerName, + sunPrinter, attrList, + &kvpList, &attrs); + _freeList(&kvpList); + + if ((result == NSL_OK) && (attrs != NULL)) + { + lresult = ldap_modify_s( + ld, (char *)printerDN, attrs); + if (lresult == LDAP_SUCCESS) + { + result = NSL_OK; + } + else + { + result = NSL_ERR_MOD_FAILED; +#ifdef DEBUG +(void) ldap_perror(ld, "ldap_modify_s"); +#endif + } + + (void) ldap_mods_free(attrs, 1); + } + } + else + { + /* + * printer-uri name change has been requested + * this is NOT allowed as it requires that + * a new printer object is created + */ + result = NSL_ERR_RENAME; /* NOT ALLOWED */ + } + + if (uriDN != NULL) + { + free(uriDN); + } + } + } + + return (result); +} /* _modifyPrinterObject */ + + + + +/* + * ***************************************************************************** + * + * Function: _checkAttributes() + * + * Description: Check that the given attribute lists does not contain any + * key words that are not allowed. + * + * Parameters: + * Input: char **list - attribute list to check + * Output: None + * + * Returns: NSL_RESULT - NSL_OK = checked okay + * + * ***************************************************************************** + */ + +static NSL_RESULT +_checkAttributes(char **list) + +{ + NSL_RESULT result = NSL_OK; + int len = 0; + char *attr = NULL; + char **p = NULL; + + /* ------ */ + + for (p = list; (p != NULL) && (*p != NULL) && (result == NSL_OK); p++) + { + /* get length of this key word */ + + for (len = 0; ((*p)[len] != '=') && ((*p)[len] != '\0'); len++); + + /* check if the key word is allowed */ + + if (strncasecmp(*p, ATTR_KVP, len) == 0) + { + /* not supported through this interface */ + result = NSL_ERR_KVP; + } + else + if (strncasecmp(*p, ATTR_BSDADDR, len) == 0) + { + /* not supported through this interface */ + result = NSL_ERR_BSDADDR; + } + else + if (strncasecmp(*p, ATTR_PNAME, len) == 0) + { + /* not supported through this interface */ + result = NSL_ERR_PNAME; + } + else + { + /* check for any others */ + + attr = strdup(*p); + attr[len] = '\0'; /* terminate the key */ + + if (_attrInList(attr, nsl_attr_notAllowed)) + { + result = NSL_ERR_NOTALLOWED; + } + } + + } + + return (result); +} /* _checkAttributes */ + + + + +/* + * ***************************************************************************** + * + * Function: _addLDAPmodValue() + * + * Description: Add the given attribute and its value to the LDAPMod array. + * If this is the first entry in the array then create it. + * + * Parameters: + * Input: LDAPMod ***attrs - array to update + * char *type - attribute to add into array + * char *value - attribute value + * Output: None + * + * Returns: NSL_RESULT - NSL_OK = added okay + * + * ***************************************************************************** + */ + +static NSL_RESULT +_addLDAPmodValue(LDAPMod ***attrs, char *type, char *value) + +{ + int i = 0; + int j = 0; + NSL_RESULT result = NSL_OK; + + /* ---------- */ + + if ((attrs != NULL) && (type != NULL) && (value != NULL)) + { +#ifdef DEBUG +printf("_addLDAPmodValue() type='%s', value='%s'\n", type, value); +#endif + /* search the existing LDAPMod array for the attribute */ + + for (i = 0; *attrs != NULL && (*attrs)[i] != NULL; i++) + { + if (strcasecmp((*attrs)[i]->mod_type, type) == 0) + { + break; + } + } + + if (*attrs == NULL) + { + /* array empty so create it */ + + *attrs = (LDAPMod **)calloc(1, 2 * sizeof (LDAPMod *)); + if (*attrs != NULL) + { + i = 0; + } + else + { + result = NSL_ERR_MEMORY; + } + + } + else + if ((*attrs)[i] == NULL) + { + *attrs = (LDAPMod **) + realloc(*attrs, (i+2) * sizeof (LDAPMod *)); + if (*attrs == NULL) + { + result = NSL_ERR_MEMORY; + } + } + } + else + { + result = NSL_ERR_INTERNAL; + } + + if (result == NSL_OK) + { + if ((*attrs)[i] == NULL) + { + /* We've got a new slot. Create the new mod. */ + + (*attrs)[i] = (LDAPMod *) malloc(sizeof (LDAPMod)); + if ((*attrs)[i] != NULL) + { + (*attrs)[i]->mod_op = LDAP_MOD_ADD; + (*attrs)[i]->mod_type = strdup(type); + (*attrs)[i]->mod_values = (char **) + malloc(2 * sizeof (char *)); + if ((*attrs)[i]->mod_values != NULL) + { + (*attrs)[i]->mod_values[0] = + strdup(value); + (*attrs)[i]->mod_values[1] = NULL; + (*attrs)[i+1] = NULL; + } + else + { + result = NSL_ERR_MEMORY; + } + } + else + { + result = NSL_ERR_MEMORY; + } + } + + else + { + /* Found an existing entry so add value to it */ + + for (j = 0; (*attrs)[i]->mod_values[j] != NULL; j++); + + (*attrs)[i]->mod_values = + (char **)realloc((*attrs)[i]->mod_values, + (j + 2) * sizeof (char *)); + if ((*attrs)[i]->mod_values != NULL) + { + (*attrs)[i]->mod_values[j] = strdup(value); + (*attrs)[i]->mod_values[j+1] = NULL; + } + else + { + result = NSL_ERR_MEMORY; + } + } + } + + return (result); +} /* _addLDAPmodValue */ + + + + +/* + * ***************************************************************************** + * + * Function: _modLDAPmodValue() + * + * Description: Add the given attribute modify operation and its value into + * the LDAPMod array. This will either be a "replace" or a + * "delete"; value = null implies a "delete". + * If this is the first entry in the array then create it. + * + * Parameters: + * Input: LDAPMod ***attrs - array to update + * char *type - attribute to modify + * char *value - attribute value, null implies "delete" + * Output: None + * + * Returns: NSL_RESULT - NSL_OK = added okay + * + * ***************************************************************************** + */ + +static NSL_RESULT +_modLDAPmodValue(LDAPMod ***attrs, char *type, char *value) + +{ + int i = 0; + int j = 0; + NSL_RESULT result = NSL_OK; + + /* ---------- */ + + if ((attrs != NULL) && (type != NULL)) + { +#ifdef DEBUG +if (value != NULL) +printf("_modLDAPmodValue() REPLACE type='%s', value='%s'\n", type, value); +else +printf("_modLDAPmodValue() DELETE type='%s'\n", type); +#endif + /* search the existing LDAPMod array for the attribute */ + + for (i = 0; *attrs != NULL && (*attrs)[i] != NULL; i++) + { + if (strcasecmp((*attrs)[i]->mod_type, type) == 0) + { + break; + } + } + + if (*attrs == NULL) + { + /* array empty so create it */ + + *attrs = (LDAPMod **)calloc(1, 2 * sizeof (LDAPMod *)); + if (*attrs != NULL) + { + i = 0; + } + else + { + result = NSL_ERR_MEMORY; + } + + } + else + if ((*attrs)[i] == NULL) + { + /* attribute not found in array so add slot for it */ + + *attrs = (LDAPMod **) + realloc(*attrs, (i+2) * sizeof (LDAPMod *)); + if (*attrs == NULL) + { + result = NSL_ERR_MEMORY; + } + } + } + else + { + result = NSL_ERR_INTERNAL; + } + + if (result == NSL_OK) + { + if ((*attrs)[i] == NULL) + { + /* We've got a new slot. Create the new mod entry */ + + (*attrs)[i] = (LDAPMod *) malloc(sizeof (LDAPMod)); + if (((*attrs)[i] != NULL) && (value != NULL)) + { + /* Do an attribute replace */ + + (*attrs)[i]->mod_op = LDAP_MOD_REPLACE; + (*attrs)[i]->mod_type = strdup(type); + (*attrs)[i]->mod_values = (char **) + malloc(2 * sizeof (char *)); + if ((*attrs)[i]->mod_values != NULL) + { + (*attrs)[i]->mod_values[0] = + strdup(value); + (*attrs)[i]->mod_values[1] = NULL; + (*attrs)[i+1] = NULL; + } + else + { + result = NSL_ERR_MEMORY; + } + } + else + if ((*attrs)[i] != NULL) + { + /* value is null so do an attribute delete */ + + (*attrs)[i]->mod_op = LDAP_MOD_DELETE; + (*attrs)[i]->mod_type = strdup(type); + (*attrs)[i]->mod_values = NULL; + (*attrs)[i+1] = NULL; + } + else + { + result = NSL_ERR_MEMORY; /* malloc failed */ + } + } + + else + { + /* Found an existing entry so add value to it */ + + if (value != NULL) + { + /* add value to attribute's replace list */ + + if ((*attrs)[i]->mod_op == LDAP_MOD_REPLACE) + { + for (j = 0; + (*attrs)[i]->mod_values[j] != NULL; j++); + + (*attrs)[i]->mod_values = + (char **)realloc((*attrs)[i]->mod_values, + (j + 2) * sizeof (char *)); + if ((*attrs)[i]->mod_values != NULL) + { + (*attrs)[i]->mod_values[j] = + strdup(value); + (*attrs)[i]->mod_values[j+1] = NULL; + } + else + { + result = NSL_ERR_MEMORY; + } + } + else + { + /* Delete and replace not allowed */ + result = NSL_ERR_MULTIOP; + } + } + + else + { + /* + * attribute delete - so free any existing + * entries in the value array + */ + + (*attrs)[i]->mod_op = LDAP_MOD_DELETE; + + if ((*attrs)[i]->mod_values != NULL) + { + for (j = 0; + (*attrs)[i]->mod_values[j] != NULL; + j++) + { + free((*attrs)[i]->mod_values[j]); + } + + free((*attrs)[i]->mod_values); + (*attrs)[i]->mod_values = NULL; + } + } + } + } + + return (result); +} /* _modLDAPmodValue */ + + + + + +/* + * ***************************************************************************** + * + * Function: _constructAddLDAPMod() + * + * Description: For the given attribute list construct an + * LDAPMod array for the printer object to be added. Default + * attribute values are included. + * + * Parameters: + * Input: + * uchar_t *printerName - Name of printer to be added + * char **attrList - user specified attribute values list + * Output: LDAPMod ***attrs - pointer to the constructed array + * + * Returns: NSL_RESULT - NSL_OK = constructed okay + * + * ***************************************************************************** + */ + +static NSL_RESULT +_constructAddLDAPMod(uchar_t *printerName, char **attrList, LDAPMod ***attrs) + +{ + NSL_RESULT result = NSL_ERROR; + int len = 0; + char **p = NULL; + char *value = NULL; + char *attr = NULL; + + /* ---------- */ + + if ((printerName != NULL) && + ((attrList != NULL) && (attrList[0] != NULL)) && (attrs != NULL)) + { + *attrs = NULL; + + /* + * setup printer object attribute values in an LDAPMod structure + */ + result = _addLDAPmodValue(attrs, ATTR_OCLASS, OCV_TOP); + if (result == NSL_OK) + { + /* Structural Objectclass */ + result = + _addLDAPmodValue(attrs, ATTR_OCLASS, OCV_PSERVICE); + } + if (result == NSL_OK) + { + result = _addLDAPmodValue(attrs, + ATTR_OCLASS, OCV_PABSTRACT); + } + if (result == NSL_OK) + { + result = _addLDAPmodValue(attrs, + ATTR_OCLASS, OCV_SUNPRT); + } + if (result == NSL_OK) + { + result = _addLDAPmodValue(attrs, + ATTR_PNAME, (char *)printerName); + } + + /* + * Now work through the user supplied attribute + * values list and add them into the LDAPMod array + */ + + for (p = attrList; + (p != NULL) && (*p != NULL) && (result == NSL_OK); p++) + { + /* get length of this key word */ + + for (len = 0; + ((*p)[len] != '=') && ((*p)[len] != '\0'); len++); + + if ((strlen(*p) > len+1)) + { + attr = strdup(*p); + attr[len] = '\0'; + value = strdup(&attr[len+1]); + + /* handle specific Key Value Pairs (KVP) */ + + if (strcasecmp(attr, NS_KEY_BSDADDR) == 0) + { + /* use LDAP attribute name */ + free(attr); + attr = strdup(ATTR_BSDADDR); + } + else + if (_attrInLDAPList(attr) == 0) + { + /* + * Non-LDAP attribute so use LDAP + * KVP attribute and the given KVP + * as the value, ie. + * sun-printer-kvp=description=printer + */ + free(attr); + attr = strdup(ATTR_KVP); + value = strdup(*p); + } + + /* add it into the LDAPMod array */ + + result = _addLDAPmodValue(attrs, attr, value); + + free(attr); + free(value); + } + } /* for */ + + if ((result != NSL_OK) && (*attrs != NULL)) + { + (void) ldap_mods_free(*attrs, 1); + attrs = NULL; + } + } + else + { + result = NSL_ERR_INTERNAL; + } + + return (result); +} /* _constructAddLDAPMod */ + + + + + + + +/* + * ***************************************************************************** + * + * Function: _constructModLDAPMod() + * + * Description: For the given modify attribute list, construct an + * LDAPMod array for the printer object to be modified + * + * Parameters: + * Input: uchar_t *printerName - name of printer to be modified + * int sunPrinter - Boolean; object is a sunPrinter + * char **attrList - user specified attribute values list + * char ***oldKVPList - current list of KVP values on object + * Output: LDAPMod ***attrs - pointer to the constructed array + * + * Returns: NSL_RESULT - NSL_OK = constructed okay + * + * ***************************************************************************** + */ + +static NSL_RESULT +_constructModLDAPMod(uchar_t *printerName, int sunPrinter, char **attrList, + char ***oldKVPList, LDAPMod ***attrs) + +{ + NSL_RESULT result = NSL_OK; + int len = 0; + int kvpUpdated = 0; + int kvpExists = 0; + char **p = NULL; + char *value = NULL; + char *attr = NULL; + + /* ---------- */ + + if ((printerName != NULL) && + ((attrList != NULL) && (attrList[0] != NULL)) && (attrs != NULL)) + { + *attrs = NULL; + + if ((oldKVPList != NULL) && (*oldKVPList != NULL)) + { + kvpExists = 1; + } + + if (!sunPrinter) + { + /* + * The object was previously not a sunPrinter, so + * add the required objectclass attribute value, and + * ensure it has the printername attribute. + */ + result = _addLDAPmodValue(attrs, + ATTR_OCLASS, OCV_SUNPRT); + if (result == NSL_OK) + { + result = _modLDAPmodValue(attrs, + ATTR_PNAME, (char *)printerName); + } + } + + /* + * work through the user supplied attribute + * values list and add them into the LDAPMod array depending + * on if they are a replace or delete attribute operation, + * a "null value" means delete. + */ + + for (p = attrList; + (p != NULL) && (*p != NULL) && (result == NSL_OK); p++) + { + /* get length of this key word */ + + for (len = 0; + ((*p)[len] != '=') && ((*p)[len] != '\0'); len++); + + if ((strlen(*p) > len+1)) + { + attr = strdup(*p); + attr[len] = '\0'; + value = strdup(&attr[len+1]); + + /* handle specific Key Value Pairs (KVP) */ + + if ((_attrInLDAPList(attr) == 0) && + (strcasecmp(attr, NS_KEY_BSDADDR) != 0)) + { + /* + * Non-LDAP attribute so use LDAP + * KVP attribute and the given KVP as + * the value, ie. + * sun-printer-kvp=description=printer + */ + result = _modAttrKVP(*p, oldKVPList); + kvpUpdated = 1; + } + + else + { + if (strcasecmp(attr, NS_KEY_BSDADDR) == + 0) + { + /* + * use LDAP bsdaddr attribute + * name + */ + free(attr); + attr = strdup(ATTR_BSDADDR); + } + + /* + * else + * use the supplied attribute name + */ + + /* add it into the LDAPMod array */ + + result = _modLDAPmodValue(attrs, + attr, value); + } + + free(attr); + free(value); + } + + else + if (strlen(*p) >= 1) + { + /* handle attribute DELETE request */ + + attr = strdup(*p); + if (attr[len] == '=') + { + /* terminate "attribute=" */ + attr[len] = '\0'; + } + + /* handle specific Key Value Pairs (KVP) */ + + if (strcasecmp(attr, NS_KEY_BSDADDR) == 0) + { + /* use LDAP bsdaddr attribute name */ + result = _modLDAPmodValue(attrs, + ATTR_BSDADDR, NULL); + } + else + if (_attrInLDAPList(attr) == 0) + { + /* + * Non-LDAP kvp, so sort items + * in the kvp list + */ + result = _modAttrKVP(*p, oldKVPList); + kvpUpdated = 1; + } + else + { + result = _modLDAPmodValue(attrs, + attr, NULL); + } + + free(attr); + } + } /* for */ + + if ((result == NSL_OK) && (kvpUpdated)) + { + result = _attrAddKVP(attrs, *oldKVPList, kvpExists); + } + + if ((result != NSL_OK) && (*attrs != NULL)) + { + (void) ldap_mods_free(*attrs, 1); + *attrs = NULL; + } + } + else + { + result = NSL_ERR_INTERNAL; + } + + return (result); +} /* _constructModLDAPMod */ + + + + + + +/* + * ***************************************************************************** + * + * Function: _compareURIinDNs() + * + * Description: For the 2 given printer object DNs compare the naming part + * part of the DN (printer-uri) to see if they are the same. + * + * Note: This function only returns "compare failed" if their URI don't + * compare. Problems with the dn etc., return a good compare + * because I don't want us to create a new object for these + * + * Parameters: + * Input: uchar_t *dn1 + * uchar_t *dn2 + * Output: None + * + * Returns: NSL_RESULT - NSL_OK = URIs are the same + * + * ***************************************************************************** + */ + +static NSL_RESULT +_compareURIinDNs(uchar_t *dn1, uchar_t *dn2) + +{ + NSL_RESULT result = NSL_OK; + uchar_t *DN1 = NULL; + uchar_t *DN2 = NULL; + char *p1 = NULL; + char *p2 = NULL; + + /* --------- */ + + if ((dn1 != NULL) && (dn2 != NULL)) + { + DN1 = (uchar_t *)strdup((char *)dn1); + DN2 = (uchar_t *)strdup((char *)dn2); + + /* terminate each string after the printer-uri */ + + p1 = strstr((char *)DN1, PCONTAINER); + /* move back to the comma */ + while ((p1 != NULL) && (*p1 != ',') && (p1 >= (char *)DN1)) + { + p1--; + } + + p2 = strstr((char *)DN2, PCONTAINER); + /* move back to the comma */ + while ((p2 != NULL) && (*p2 != ',') && (p2 >= (char *)DN2)) + { + p2--; + } + + if ((*p1 == ',') && (*p2 == ',')) + { + *p1 = '\0'; /* re-terminate it */ + *p2 = '\0'; /* re-terminate it */ + + /* do the compare */ + + /* + * Note: SHOULD really normalise the 2 DNs before + * doing the compare + */ +#ifdef DEBUG +printf("_compareURIinDNs() @1 (%s) (%s)\n", DN1, DN2); +#endif + if (strcasecmp((char *)DN1, (char *)DN2) != 0) + { + result = NSL_ERROR; + } + + } + + free(DN1); + free(DN2); + } + + return (result); +} /* _compareURIinDNs */ + + + + + + + +/* + * ***************************************************************************** + * + * Function: _getThisNSDomainDN() + * + * Description: Get the current Name Service Domain DN + * This is extracted from the result of executing ldaplist. + * + * Note: Do it this way until the NS LDAP library interface is + * made public. + * + * Parameters: + * Input: None + * Output: None + * + * Returns: uchar_t* - pointer to NS Domain DN (The caller should free this + * returned memory). + * + * ***************************************************************************** + */ + +#define LDAPLIST_D "/usr/bin/ldaplist -d 2>&1" +#define DNID "dn: " + +static uchar_t * +_getThisNSDomainDN(void) + +{ + uchar_t *domainDN = NULL; + char *cp = NULL; + char buf[BUFSIZ] = ""; + + /* --------- */ + + if (_popen(LDAPLIST_D, buf, sizeof (buf)) == 0) + { + if ((cp = strstr(buf, DNID)) != NULL) + { + cp += strlen(DNID); /* increment past "dn: " label */ + domainDN = (uchar_t *)strdup(cp); + + if ((cp = strchr((char *)domainDN, '\n')) != NULL) + { + *cp = '\0'; /* terminate it */ + } + } + } + + return (domainDN); +} /* _getThisNSDomainDN */ + + + + + +/* + * ***************************************************************************** + * + * Function: _popen() + * + * Description: General popen function. The caller should always use a full + * path cmd. + * + * Parameters: + * Input: char *cmd - command line to execute + * char *buffer - ptr to buffer to put result in + * int size - size of result buffer + * Output: None + * + * Returns: int - 0 = opened okay + * + * ***************************************************************************** + */ + +static int +_popen(char *cmd, char *buffer, int size) + +{ + int result = -1; + int rsize = 0; + FILE *fptr; + char safe_cmd[BUFSIZ]; + char linebuf[BUFSIZ]; + + /* -------- */ + + if ((cmd != NULL) && (buffer != NULL) && (size != 0)) + { + (void) strcpy(buffer, ""); + (void) strcpy(linebuf, ""); + (void) snprintf(safe_cmd, BUFSIZ, "IFS=' \t'; %s", cmd); + + if ((fptr = popen(safe_cmd, "r")) != NULL) + { + while ((fgets(linebuf, BUFSIZ, fptr) != NULL) && + (rsize < size)) + { + rsize = strlcat(buffer, linebuf, size); + if (rsize >= size) + { + /* result is too long */ + (void) memset(buffer, '\0', size); + } + } + + if (strlen(buffer) > 0) + { + result = 0; + } + + (void) pclose(fptr); + } + } + + return (result); +} /* popen */ + + +/* + * ***************************************************************************** + * + * Function: _attrInList() + * + * Description: For the given list check if the attribute is it + * + * Parameters: + * Input: char *attr - attribute to check + * char **list - list of attributes to check against + * Output: None + * + * Returns: int - TRUE = attr found in list + * + * ***************************************************************************** + */ + +static int +_attrInList(char *attr, const char **list) + +{ + int result = 0; + int j; + + /* ------- */ + + if ((attr != NULL) && (list != NULL)) + { + for (j = 0; (list[j] != NULL) && (result != 1); j++) + { + if (strcasecmp(list[j], attr) == 0) + { + result = 1; /* found */ + } + } + } + + return (result); +} /* _attrInList */ + + + + +/* + * ***************************************************************************** + * + * Function: _attrInLDAPList() + * + * Description: Checks to see if the given attribute is an LDAP printing + * attribute, ie. is either in an IPP objectclass or the + * sun printer objectclass. Note: some attributes are handled + * specifically outside this function, so are excluded from + * the lists that are checked. + * + * Parameters: + * Input: char *attr - attribute to check + * Output: None + * + * Returns: int - TRUE = attr found in list + * + * ***************************************************************************** + */ + +static int +_attrInLDAPList(char *attr) + +{ + int result = 0; + + /* ------- */ + + if (_attrInList(attr, nsl_attr_printerService)) + { + result = 1; /* in list */ + } + else + if (_attrInList(attr, nsl_attr_printerIPP)) + { + result = 1; /* in list */ + } + else + if (_attrInList(attr, nsl_attr_sunPrinter)) + { + result = 1; /* in list */ + } + + return (result); +} /* _attrInLDAPList */ + + + + +/* + * ***************************************************************************** + * + * Function: _getCurrentKVPValues() + * + * Description: For the given printer object read the current set of values + * the object has for the sun-printer-kvp (Key Value pair) + * + * Parameters: + * Input: LDAP *ld - existing ldap connection descriptor + * char *objectDN - DN to search for + * Output: char ***list - returned set of kvp values + * + * Result: NSL_RESULT - NSL_OK = object exists + * + * ***************************************************************************** + */ + +static NSL_RESULT +_getCurrentKVPValues(LDAP *ld, uchar_t *objectDN, char ***list) + +{ + NSL_RESULT result = NSL_ERR_UNKNOWN_PRINTER; + int sresult = LDAP_NO_SUCH_OBJECT; + int i = 0; + LDAPMessage *ldapMsg; + char *requiredAttrs[2] = { ATTR_KVP, NULL }; + LDAPMessage *ldapEntry = NULL; + char *entryAttrib = NULL; + char **attribValues = NULL; + BerElement *berElement = NULL; + + /* ---------- */ + + if ((list != NULL) && (ld != NULL) && (objectDN != NULL)) + { + /* search for this Printer in the directory */ + + sresult = ldap_search_s(ld, (char *)objectDN, LDAP_SCOPE_BASE, + "(objectclass=*)", requiredAttrs, 0, &ldapMsg); + if (sresult == LDAP_SUCCESS) + { + /* + * check that the object exists and extract its + * KVP attribute values + */ + ldapEntry = ldap_first_entry(ld, ldapMsg); + if (ldapEntry != NULL) + { + entryAttrib = ldap_first_attribute(ld, + ldapEntry, &berElement); + if ((entryAttrib != NULL) && + (strcasecmp(entryAttrib, ATTR_KVP) == 0)) + + { +#ifdef DEBUG +printf("Attribute: %s, its values are:\n", entryAttrib); +#endif + /* + * add each KVP value to the list + * that we will return + */ + attribValues = ldap_get_values( + ld, ldapEntry, entryAttrib); + for (i = 0; + attribValues[i] != NULL; i++) + { + *list = (char **) + list_append((void **)*list, + strdup(attribValues[i])); +#ifdef DEBUG +printf("\t%s\n", attribValues[i]); +#endif + } + (void) ldap_value_free(attribValues); + } + + if ((entryAttrib != NULL) && + (berElement != NULL)) + { + ber_free(berElement, 0); + } + + + /* object found */ + result = NSL_OK; + } + + (void) ldap_msgfree(ldapMsg); + } + } + + else + { + result = NSL_ERR_INTERNAL; + } + + return (result); +} /* _getCurrentKVPValues */ + + + +/* + * ***************************************************************************** + * + * Function: _freeList() + * + * Description: Free the list created by list_append() where the items in + * the list have been strdup'ed. + * + * Parameters: + * Input: char ***list - returned set of kvp values + * + * Result: void + * + * ***************************************************************************** + */ + +static void +_freeList(char ***list) + +{ + int i = 0; + + /* ------ */ + + if (list != NULL) + { + if (*list != NULL) + { + for (i = 0; (*list)[i] != NULL; i++) + { + free((*list)[i]); + } + free(*list); + } + + *list = NULL; + } +} /* _freeList */ + + + +/* + * ***************************************************************************** + * + * Function: _modAttrKVP() + * + * Description: Sort out the KVP attribute value list, such that this new + * value takes precidence over any existing value in the list. + * The current list is updated to remove this key, and the new + * key "value" is added to the list, eg. for + * value: bbb=ddddd + * and kvpList: + * aaa=yyyy + * bbb=zzzz + * ccc=xxxx + * the resulting kvpList is: + * aaa=yyyy + * ccc=xxxx + * bbb=ddddd + * + * Note: When all new values have been handled the function _attrAddKVP() + * must be called to add the "new list" values into the + * LDAPMod array. + * + * Parameters: + * Input: char *value - Key Value Pair to process, + * eg. aaaaa=hhhhh, where aaaaa is the key + * char ***kvpList - list of current KVP values + * Output: char ***kvpList - updated list of KVP values + * + * Returns: NSL_RESULT - NSL_OK = done okay + * + * ***************************************************************************** + */ + +static NSL_RESULT +_modAttrKVP(char *value, char ***kvpList) + +{ + NSL_RESULT result = NSL_ERR_INTERNAL; + int i = 0; + int inList = 0; + int keyDelete = 0; + char *key = NULL; + char **p = NULL; + char **newList = NULL; + + /* ------- */ + + if ((value != NULL) && (kvpList != NULL)) + { + result = NSL_OK; + + /* extract "key" from value */ + + key = strdup(value); + + for (i = 0; ((key)[i] != '=') && ((key)[i] != '\0'); i++); + key[i] = '\0'; /* terminate the key */ + + /* Is this a request to delete a "key" value */ + + if ((value[i] == '\0') || (value[i+1] == '\0')) + { + /* this is a request to delete the key */ + keyDelete = 1; + } + + if ((*kvpList != NULL) && (**kvpList != NULL)) + { + /* + * for each item in the list remove it if the keys match + */ + for (p = *kvpList; *p != NULL; p++) + { + for (i = 0; + ((*p)[i] != '=') && ((*p)[i] != '\0'); i++); + + if ((strlen(key) == i) && + (strncasecmp(*p, key, i) == 0)) + { + inList = 1; + } + else + { + /* no match so add value to new list */ + newList = (char **)list_append( + (void **)newList, + strdup(*p)); + } + } + } + + /* + * if it was not a DELETE request add the new key value into + * the newList, otherwise we have already removed the key + */ + + if (!keyDelete) + { + newList = (char **)list_append((void **)newList, + strdup(value)); + } + + if ((newList != NULL) || (inList)) + { + /* replace old list with the newList */ + _freeList(kvpList); + *kvpList = newList; + } + + free(key); + } + + return (result); +} /* modAttrKVP */ + + + + +/* + * ***************************************************************************** + * + * Function: _attrAddKVP() + * + * Description: Process KVP items in the kvpList adding them to the + * LDAPMod modify array. If the list is empty but there were + * previously LDAP KVP values delete them. + * + * Note: This function should only be called when all the new KVP + * items have been processed by _modAttrKVP() + * + * Parameters: + * Input: LDAPMod ***attrs - array to update + * char **kvpList - list KVP values + * int kvpExists - object currently has LDAP KVP values + * Output: None + * + * Returns: NSL_RESULT - NSL_OK = done okay + * + * ***************************************************************************** + */ + +static NSL_RESULT +_attrAddKVP(LDAPMod ***attrs, char **kvpList, int kvpExists) + +{ + NSL_RESULT result = NSL_OK; + + /* ------- */ + + if (attrs != NULL) + { + if (kvpList != NULL) + { + while ((kvpList != NULL) && (*kvpList != NULL)) + { + /* add item to LDAPMod array */ + + result = + _modLDAPmodValue(attrs, ATTR_KVP, *kvpList); + + kvpList++; + } + } + else + if (kvpExists) + { + /* + * We now have no LDAP KVP values but there were + * some previously, so delete them + */ + result = _modLDAPmodValue(attrs, ATTR_KVP, NULL); + } + } + + else + { + result = NSL_ERR_INTERNAL; + } + + return (result); +} /* _attrAddKVP */ + + + + +/* + * ***************************************************************************** + * + * Function: _manageReferralCredentials() + * + * Description: This function is called if a referral request is returned by + * the origonal LDAP server during the ldap update request call, + * eg. ldap_add_s(), ldap_modify_s() or ldap_delete_s(). + * Parameters: + * Input: LDAP *ld - LDAP descriptor + * int freeit - 0 = first call to get details + * - 1 = second call to free details + * - -1 = initial store of authentication details + * Input/Output: char **dn - returns DN to bind to on master + * char **credp - returns password for DN + * int *methodp - returns authentication type, eg. simple + * + * Returns: int - 0 = okay + * + * ***************************************************************************** + */ +static int _manageReferralCredentials(LDAP *ld, char **dn, char **credp, + int *methodp, int freeit) + +{ + int result = 0; + static char *sDN = NULL; + static char *sPasswd = NULL; + static int sMethod = LDAP_AUTH_SIMPLE; + + /* -------- */ + + if (freeit == 1) + { + /* second call - free memory */ + + if ((dn != NULL) && (*dn != NULL)) + { + free(*dn); + } + + if ((credp != NULL) && (*credp != NULL)) + { + free(*credp); + } + } + + else + if ((ld != NULL) && + (dn != NULL) && (credp != NULL) && (methodp != NULL)) + { + if ((freeit == 0) && (sDN != NULL) && (sPasswd != NULL)) + { + /* first call - get the saved bind credentials */ + + *dn = strdup(sDN); + *credp = strdup(sPasswd); + *methodp = sMethod; + } + else + if (freeit == -1) + { + /* initial call - save the saved bind credentials */ + + sDN = *dn; + sPasswd = *credp; + sMethod = *methodp; + } + else + { + result = 1; /* error */ + } + } + else + { + result = 1; /* error */ + } + + return (result); +} /* _manageReferralCredentials */ |