/* Copyright (C) 2005 Luke Howard.
This file is part of the nss_ldap library.
Contributed by Luke Howard, <lukeh@padl.com>, 2005.
The nss_ldap library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The nss_ldap library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the nss_ldap library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
$Id: ldap-automount.c,v 2.10 2009/11/06 10:15:26 lukeh Exp $
*/
static char rcsId[] = "$Id: ldap-automount.c,v 2.10 2009/11/06 10:15:26 lukeh Exp $";
#include "config.h"
#ifdef HAVE_PORT_BEFORE_H
#include <port_before.h>
#endif
#if defined(HAVE_THREAD_H) && !defined(_AIX)
#include <thread.h>
#elif defined(HAVE_PTHREAD_H)
#include <pthread.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#ifdef HAVE_LBER_H
#include <lber.h>
#endif
#ifdef HAVE_LDAP_H
#include <ldap.h>
#endif
#include "ldap-nss.h"
#include "ldap-automount.h"
#include "util.h"
#ifdef HAVE_PORT_AFTER_H
#include <port_after.h>
#endif
static NSS_STATUS
_nss_ldap_parse_automount (LDAPMessage * e,
ldap_state_t * pvt,
void *result, char *buffer, size_t buflen)
{
NSS_STATUS stat;
char ***keyval = result;
stat =
_nss_ldap_assign_attrval (e, AT (automountKey), keyval[0],
&buffer, &buflen);
if (stat != NSS_SUCCESS)
return stat;
stat =
_nss_ldap_assign_attrval (e, AT (automountInformation), keyval[1],
&buffer, &buflen);
if (stat != NSS_SUCCESS)
return stat;
return NSS_SUCCESS;
}
NSS_STATUS
_nss_ldap_am_context_alloc(ldap_automount_context_t **pContext)
{
ldap_automount_context_t *context;
context = (ldap_automount_context_t *)malloc (sizeof(*context));
if (context == NULL)
{
return NSS_TRYAGAIN;
}
context->lac_state = NULL;
context->lac_dn_size = 1; /* number of slots allocated */
context->lac_dn_count = 0; /* number of slots used */
context->lac_dn_index = 0; /* enumeration index */
/* List of DNs, grown on demand */
context->lac_dn_list = (char **)malloc (context->lac_dn_size *
sizeof(char *));
if (context->lac_dn_list == NULL)
{
free (context);
return NSS_TRYAGAIN;
}
if (_nss_ldap_ent_context_init_locked (&context->lac_state) == NULL)
{
free (context->lac_dn_list);
free (context);
return NSS_UNAVAIL;
}
*pContext = context;
return NSS_SUCCESS;
}
void
_nss_ldap_am_context_free(ldap_automount_context_t **pContext)
{
ldap_automount_context_t *context;
size_t i;
context = *pContext;
if (context == NULL)
return;
if (context->lac_dn_list != NULL)
{
for (i = 0; i < context->lac_dn_count; i++)
{
#ifdef HAVE_LDAP_MEMFREE
ldap_memfree (context->lac_dn_list[i]);
#else
free (context->lac_dn_list[i]);
#endif /* HAVE_LDAP_MEMFREE */
}
free (context->lac_dn_list);
}
if (context->lac_state != NULL)
{
_nss_ldap_ent_context_release (&(context->lac_state));
}
memset (context, 0, sizeof (*context));
free (context);
*pContext = NULL;
return;
}
static NSS_STATUS
am_context_add_dn (LDAPMessage * e,
ldap_state_t * pvt,
void *result, char *buffer, size_t buflen)
{
ldap_automount_context_t *context = (ldap_automount_context_t *) result;
char *dn;
dn = _nss_ldap_get_dn (e);
if (dn == NULL)
{
return NSS_NOTFOUND;
}
if (context->lac_dn_count >= context->lac_dn_size)
{
char **new_dns;
new_dns = (char **)realloc(context->lac_dn_list,
2 * context->lac_dn_size * sizeof(char *));
if (new_dns == NULL)
{
#ifdef HAVE_LDAP_MEMFREE
ldap_memfree (dn);
#else
free (dn);
#endif /* HAVE_LDAP_MEMFREE */
return NSS_TRYAGAIN;
}
context->lac_dn_list = new_dns;
context->lac_dn_size *= 2;
}
context->lac_dn_list[context->lac_dn_count++] = dn;
return NSS_SUCCESS;
}
NSS_STATUS
_nss_ldap_am_context_init(const char *mapname, ldap_automount_context_t **pContext)
{
NSS_STATUS stat;
ldap_automount_context_t *context = NULL;
const char *no_attrs[] = { NULL };
ldap_args_t a;
ent_context_t *key = NULL;
int errnop;
*pContext = NULL;
stat = _nss_ldap_am_context_alloc (&context);
if (stat != NSS_SUCCESS)
return stat;
LA_INIT (a);
LA_TYPE (a) = LA_TYPE_STRING;
LA_STRING (a) = mapname;
do
{
stat = _nss_ldap_getent_ex (&a, &key,
(void *)context,
NULL, 0, &errnop,
_nss_ldap_filt_setautomntent,
LM_AUTOMOUNT,
no_attrs,
am_context_add_dn);
}
while (stat == NSS_SUCCESS);
if (key != NULL)
{
_nss_ldap_ent_context_release (&key);
}
if (context->lac_dn_count == 0)
{
_nss_ldap_am_context_free (&context);
return NSS_NOTFOUND;
}
else if (stat == NSS_NOTFOUND)
{
stat = NSS_SUCCESS;
}
context->lac_dn_index = 0;
*pContext = context;
return NSS_SUCCESS;
}
#ifdef HAVE_NSS_H
NSS_STATUS _nss_ldap_setautomntent(const char *mapname, void **private)
{
ldap_automount_context_t *context = NULL;
NSS_STATUS stat;
debug ("==> _nss_ldap_setautomntent");
_nss_ldap_enter ();
stat = _nss_ldap_init ();
if (stat != NSS_SUCCESS)
{
_nss_ldap_leave ();
debug ("<== _nss_ldap_setautomntent");
return stat;
}
stat = _nss_ldap_am_context_init (mapname, &context);
if (stat != NSS_SUCCESS)
{
_nss_ldap_leave ();
debug ("<== _nss_ldap_setautomntent");
return stat;
}
*private = (void *)context;
_nss_ldap_leave ();
debug ("<== _nss_ldap_setautomntent");
return stat;
}
NSS_STATUS _nss_ldap_getautomntent_r(void *private, const char **key, const char **value,
char *buffer, size_t buflen, int *errnop)
{
NSS_STATUS stat;
ldap_automount_context_t *context = (ldap_automount_context_t *)private;
ldap_args_t a;
char **keyval[2];
if (context == NULL)
return NSS_NOTFOUND;
debug ("==> _nss_ldap_getautomntent_r");
keyval[0] = (char **)key;
keyval[1] = (char **)value;
_nss_ldap_enter ();
do
{
assert (context->lac_dn_index < context->lac_dn_count);
LA_INIT (a);
LA_TYPE (a) = LA_TYPE_NONE;
LA_BASE (a) = context->lac_dn_list[context->lac_dn_index];
stat = _nss_ldap_getent_ex (&a, &context->lac_state,
(void *)keyval,
buffer, buflen, errnop,
_nss_ldap_filt_getautomntent,
LM_AUTOMOUNT,
NULL,
_nss_ldap_parse_automount);
if (stat == NSS_NOTFOUND)
{
if (context->lac_dn_index < context->lac_dn_count - 1)
context->lac_dn_index++;
else
break; /* move along, nothing more to see here */
}
}
while (stat == NSS_NOTFOUND);
_nss_ldap_leave ();
debug ("<== _nss_ldap_getautomntent_r");
return stat;
}
NSS_STATUS _nss_ldap_endautomntent(void **private)
{
ldap_automount_context_t **pContext = (ldap_automount_context_t **)private;
debug ("==> _nss_ldap_endautomntent");
_nss_ldap_enter ();
_nss_ldap_am_context_free (pContext);
/* workaround because Linux automounter spawns a lot of processes */
_nss_ldap_close ();
_nss_ldap_leave ();
debug ("<== _nss_ldap_endautomntent");
return NSS_SUCCESS;
}
NSS_STATUS _nss_ldap_getautomntbyname_r(void *private, const char *key,
const char **canon_key, const char **value,
char *buffer, size_t buflen, int *errnop)
{
NSS_STATUS stat = NSS_NOTFOUND;
ldap_automount_context_t *context = (ldap_automount_context_t *)private;
ldap_args_t a;
char **keyval[2];
size_t i;
if (context == NULL)
return NSS_NOTFOUND;
debug ("==> _nss_ldap_getautomntbyname_r");
keyval[0] = (char **)canon_key;
keyval[1] = (char **)value;
for (i = 0; i < context->lac_dn_count; i++)
{
LA_INIT (a);
LA_TYPE (a) = LA_TYPE_STRING;
LA_STRING (a) = key;
LA_BASE (a) = context->lac_dn_list[i];
/* we do not acquire lock in this case */
stat = _nss_ldap_getbyname (&a,
(void *)keyval,
buffer, buflen, errnop,
_nss_ldap_filt_getautomntbyname,
LM_AUTOMOUNT,
_nss_ldap_parse_automount);
if (stat != NSS_NOTFOUND)
{
break; /* on success or error other than not found */
}
}
debug ("<== _nss_ldap_getautomntbyname_r");
return stat;
}
#endif /* HAVE_NSS_H */