nss_ldap.c revision c1ecd8b9404ee0d96d93f02e82c441b9bb149a3d
/*
* 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 2008 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>
#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 */