ns_ldap.c revision 36e852a172cba914383d7341c988128b2c667fbd
/*
* 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
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <string.h>
#include <ctype.h>
#include <nsswitch.h>
#include <rpcsvc/nfs_prot.h>
#include <libintl.h>
#include "automount.h"
#include "../../../lib/libsldap/common/ns_sldap.h"
/*
* LDAP schema used for automounter:
*
* automountMapName: mapname i.e. auto_home, etc.
* automountKey: contains the key i.e. the mount point
* automountInformation: contains the mount options and remote mount location
* description: an optional description (not used by automounter)
*
* For example, if auto_direct has the following line of data:
*
*
* Then this would map to the the following LDAP entry:
*
* dn: automountKey=/work,automountMapName=auto_direct,...
* automountKey: /work
* objectclass: top
* objectclass: automount
*
* In this container:
*
* dn: automountMapName=auto_direct,...
* automountMapName: auto_direct
* objectClass: top
* objectClass: automountMap
*
* Note that the schema can be mapped and SSD's can be used to relocate
* the default location of these entries.
*
*/
#define CAPCHAR '%'
#define MAXERROR 4000
static char *automountKey = NULL;
static char *automountInformation = NULL;
static char *defaultFilter = NULL;
static int encode = 0;
static int mastermap_callback_ldap();
static int directmap_callback();
static int ldap_err(int);
static int ldap_match();
static int readdir_callback();
struct loadmaster_cbdata {
char *ptr1;
char **ptr2;
char ***ptr3;
};
struct loaddirect_cbdata {
char *ptr1;
char *ptr2;
char **ptr3;
char ***ptr4;
};
struct dir_cbdata {
int error;
};
static char *tosunds_str(char *);
static char *tounix_str(char *);
static int
{
char **s;
char **mappedschema = NULL;
if (mappedschema == NULL)
return (0);
for (s = mappedschema; *s != NULL; s++)
free(*s);
return (0);
}
for (s = mappedschema; *s != NULL; s++)
free(*s);
return (1);
}
static int
{
char **s;
char **mappedschema = NULL;
if (mappedschema == NULL)
return (0);
for (s = mappedschema; *s != NULL; s++)
free(*s);
return (0);
}
for (s = mappedschema; *s != NULL; s++)
free(*s);
return (1);
}
void
{
/*
* Check for version of the profile the client is using
*
* For version 1 profiles we do encoding of attributes
* and use nisMap and nisObject schema for backward compatibility.
*
* For version 2 profiles we don't do encoding and use
* automountMap and automount as default attributes (which can
* then be overridden in libsldap if schema mapping is configured
* in the profile).
*
* If profile version is not available, use version 2 as default
* and syslog message.
*/
enum __nsw_parse_err pserr;
int ldap_configured = 0;
#ifdef lint
#endif /* lint */
/* get nsswitch info of "automount */
/* find out if LDAP backend is configured */
ldap_configured = 1;
break;
}
}
/* free conf at the end of "if" bracket */
(void) __nsw_freeconfig(conf);
}
/* if ldap is not configured, init_ldap is a no op */
if (!ldap_configured)
return;
" that is used (%d, %s). Using version 2 profile"
(void) __ns_ldap_freeError(&errorp);
} else {
v2 = 0;
(void) __ns_ldap_freeParam(¶mVal);
}
if (v2) {
if (trace > 1)
automountKey = "automountKey";
automountInformation = "automountInformation";
defaultFilter = "(&(objectClass=automount)(automountKey=%s))";
/* check for automountMapName mapped to nisMapName */
return;
/* check for automountKey mapped to cn */
return;
/* check for automountInformation mapped to nisMapEntry */
return;
/* check for automountMap mapped to nisMap */
return;
/* check for automount mapped to nisObject */
return;
if (trace > 1)
encode = 1;
} else {
if (trace > 1) {
}
encode = 1;
automountKey = "cn";
automountInformation = "nisMapEntry";
defaultFilter = "(&(objectClass=nisObject)(cn=%s))";
}
}
/*ARGSUSED*/
int
{
char *lp;
int nserr;
if (trace > 1)
if (trace > 1) {
}
if (iswildcard)
*iswildcard = FALSE;
if (nserr) {
if (nserr == __NSW_NOTFOUND) {
/* Try the default entry "*" */
&ldap_len)))
goto done;
else {
if (iswildcard)
*iswildcard = TRUE;
}
} else
goto done;
}
/*
* at this point we are sure that ldap_match
* succeeded so massage the entry by
* 1. ignoring # and beyond
* 2. trim the trailing whitespace
*/
*lp = '\0';
if (len == 0) {
goto done;
}
*lp-- = '\0';
goto done;
}
done:
if (ldap_line)
if (trace > 1)
return (nserr);
}
static int
{
char searchfilter[LDAP_FILT_MAXSIZ];
int res, attr_found;
char *ldapkey;
int i;
if (trace > 1) {
}
/*
* need to handle uppercase characters in the key because LDAP
* searches are case insensitive. Note, key = attribute automountKey.
*/
if (encode)
else
if (trace > 1) {
}
if (trace > 1)
searchfilter, map);
if (trace > 1) {
if (res != NS_LDAP_SUCCESS)
trace_prt(1,
" ldap_match: __ns_ldap_list FAILED (%d)\n", res);
else
}
if (errp) {
if (verbose) {
gettext("ldap server can't list map,"
" '%s': '%s' - '%d'."),
}
} else {
if (verbose) {
char *errmsg;
}
}
if (result)
}
if (trace > 1)
if (errp)
if (result)
return (__NSW_NOTFOUND);
}
/*
* get value of attribute nisMapEntry. This attribute contains a
* list of mount options AND mount location for a particular mount
* point (key).
* For example:
*
* key: /work
* ^^^^^
* (mount point)
*
* ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
* ( mount options ) (remote mount location)
*
*/
attr_found = 0;
for (i = 0; i < entry->attr_count; i++) {
char *attrval;
attr_found = 1;
if (encode)
else
/*
* so check for the length; it should be less than
* LINESZ
*/
"ldap server map %s, entry for %s"
" is too long %d chars (max %d)",
return (__NSW_UNAVAIL);
}
return (__NSW_UNAVAIL);
}
break;
}
}
if (!attr_found)
return (__NSW_NOTFOUND);
if (trace > 1)
return (__NSW_SUCCESS);
}
int
{
char searchfilter[LDAP_FILT_MAXSIZ];
int res;
struct loadmaster_cbdata master_cbdata;
if (trace > 1)
/* filter gets all the entries for the specified mapname */
if (trace > 1)
(void *) &master_cbdata);
if (trace > 1)
trace_prt(1,
"loadmaster_ldap: __ns_ldap_list just returned: %d\n",
res);
if (res != NS_LDAP_SUCCESS) {
if (errp) {
if (verbose) {
"ldap server can't list map,"
"'%s': '%s' - '%d'."),
}
} else {
if (verbose) {
char *errmsg;
}
}
if (result)
}
if (trace > 1)
trace_prt(1,
"loadmaster_ldap: calling __ns_ldap_freeResult...\n");
if (trace > 1)
trace_prt(1,
"loadmaster_ldap: about to return __NSW_SUCCESS...\n");
return (__NSW_SUCCESS);
}
int
{
char searchfilter[LDAP_FILT_MAXSIZ];
int res;
struct loaddirect_cbdata direct_cbdata;
if (trace > 1) {
}
/* filter gets all the entries for the specified mapname */
if (trace > 1)
directmap_callback, (void *) &direct_cbdata);
if (res != NS_LDAP_SUCCESS) {
if (errp) {
if (verbose) {
gettext("ldap server can't list map,"
" '%s': '%s' - '%d'."),
}
} else {
if (verbose) {
char *errmsg;
}
}
if (result)
}
return (__NSW_SUCCESS);
}
static int
{
if (trace > 1)
switch (err) {
case NS_LDAP_SUCCESS:
return (__NSW_SUCCESS);
case NS_LDAP_NOTFOUND:
return (__NSW_NOTFOUND);
case NS_LDAP_PARTIAL:
return (__NSW_TRYAGAIN);
default:
return (__NSW_UNAVAIL);
}
}
static int
{
int key_len, contents_len;
int i;
if (trace > 1) {
if (entry) {
trace_prt(1,
"mastermap_callback_ldap: entry->attr_count=[ %d ]\n",
entry->attr_count);
}
}
/*
* For the current entry, obtain the values of the cn and the
* nisMapEntry attributes and the length of each value (cn=key,
* nisMapEntry=contents).
* We skip the description. Even though LDAP allows for multiple
* values per attribute, we take only the 1st value for each
* attribute because the automount data is organized as such.
*/
key_len = 0;
contents_len = 0;
for (i = 0; i < entry->attr_count; i++) {
if (trace > 1) {
trace_prt(1,
"mastermap_callback_ldap: attr[%d]: %s=%s\n",
}
if (encode)
else
LINESZ);
if (trace > 1) {
trace_prt(1,
"mastermap_callback_ldap: contents=[ %s ],"
" contents_len=[ %d ]\n",
}
}
if (encode)
else
LINESZ);
if (trace > 1) {
trace_prt(1,
"mastermap_callback_ldap: key=[ %s ],"
" key_len=[ %d ]\n",
}
}
}
return (0);
return (0);
contents++;
return (0);
return (0);
if (trace > 1)
for (i = 0; i < LINESZ; i++)
qbuff[i] = ' ';
"%s in ldap server map: entry too long (max %d chars)",
return (0);
}
if (trace > 1)
"%s in ldap server map: entry too long (max %d chars)",
return (0);
}
pmap++; /* skip blanks in front of map */
opts++;
if (*opts) {
*opts++ = '\0';
opts++;
if (*opts == '-')
opts++;
else
}
/*
* Check for no embedded blanks.
*/
if (trace > 1)
trace_prt(1,
"mastermap_callback_ldap: dir=[ %s ], pmap=[ %s ]\n",
} else {
/* get the value for the dn */
for (i = 0; i < entry->attr_count; i++) {
== 0) {
break;
}
}
"Warning: invalid entry for %s in ldap server"
" dn: %s ignored.\n",
}
if (trace > 1)
return (0);
}
static int
{
char *key;
char dir[256];
int key_len;
int i;
/*
* For the current entry, obtain the value and length of the cn i.e.
* the contents of key and its key length.
*/
key_len = 0;
for (i = 0; i < entry->attr_count; i++) {
if (encode)
else
break;
}
}
return (0);
return (0);
return (0);
}
int
{
char searchfilter[LDAP_FILT_MAXSIZ];
int res;
struct dir_cbdata readdir_cbdata;
#ifdef lint
#endif /* lint */
if (trace > 1)
*error = 0;
/* filter gets all the entries for the specified mapname */
if (trace > 1)
if (trace > 1)
res);
if (readdir_cbdata.error)
if (errp) {
if (verbose) {
"ldap server can't list map,"
" '%s': '%s' - '%d'."),
}
} else {
if (verbose) {
char *errmsg;
}
}
if (result)
if (*error == 0)
}
if (result)
return (__NSW_SUCCESS);
}
static int
{
char *key;
int key_len;
int i;
if (trace > 1)
/*
* For the current entry, obtain the value and length of the cn i.e. the
* contents of key and its key length.
*/
key_len = 0;
if (trace > 1)
entry->attr_count);
for (i = 0; i < entry->attr_count; i++) {
if (trace > 1)
trace_prt(1,
"readdir_callback: attr->attrname=[ %s ]\n",
if (encode)
else
if (trace > 1)
trace_prt(1,
"readdir_callback: key=[ %s ], key_len=[ %d ]\n",
break;
}
}
return (0);
return (0);
/*
* Wildcard entry should be ignored - following entries should continue
* to be read to corroborate with the way we search for entries in
* LDAP, i.e., first for an exact key match and then a wildcard
* if there's no exact key match.
*/
return (0);
return (1);
}
if (trace > 1)
return (0);
}
/*
* Puts CAPCHAR in front of uppercase characters or surrounds a set of
* contiguous uppercase characters with CAPCHARS and square brackets.
*
* For example (assuming CAPCHAR = '%'):
*
* if str = Abc, it returns %Abc
* if str = ABc, it returns %[AB]c
* if str = AbC, it returns %Ab%C
*
*/
static char *
tosunds_str(char *str)
{
#ifdef NEWCAP
#endif
j = 0;
/* Check the current element */
#ifdef NEWCAP
/* check the next element */
if (openBracket == FALSE) {
openBracket = TRUE;
j += 2;
}
} else {
if (openBracket == FALSE) {
j++;
} else {
openBracket = FALSE;
closeBracket = TRUE;
}
}
#else
#endif
}
j++;
#ifdef NEWCAP
if (closeBracket == TRUE) {
buf[j] = ']';
j++;
}
#endif
if (j >= BUFSIZ) {
break;
}
}
if (er) {
} else
buf[j] = '\0';
return (buf);
}
/*
* Reverses what tosunds_str() did
*/
static char *
tounix_str(char *str)
{
int i, j;
int openBracket = FALSE;
j = 0;
if (str[i] == '%') {
i += 1;
i += 2;
openBracket = TRUE;
}
} else if (str[i] == ']') {
i += 1;
openBracket = FALSE;
}
j++;
}
return (buf);
}