/* Copyright (c) 2004 Michael Bushkov <bushman@rsu.ru> */
/*
* Copyright (C) 1997-2003 Luke Howard. This file is part of the nss_ldap library. Contributed by Luke Howard, <lukeh@padl.com>, 1997.
*
* 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.
*/
/*static char rcsId[] =
"$Id: ldap-grp.c,v 2.50 2003/01/30 10:06:45 lukeh Exp $";(*/
#include "config.h"
#ifdef HAVE_PORT_BEFORE_H
#include <port_before.h>
#endif
#ifdef HAVE_THREAD_H
#include <thread.h>
#elif defined(HAVE_PTHREAD_H)
#include <pthread.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/param.h>
#include <grp.h>
#ifdef HAVE_LBER_H
#include <lber.h>
#endif
#ifdef HAVE_LDAP_H
#include <ldap.h>
#endif
#ifndef HAVE_SNPRINTF
#include "snprintf.h"
#endif
#include "ldap-nss.h"
#include "ldap-grp.h"
#include "globals.h"
#include "util.h"
#include "bsdtss.h"
#ifdef HAVE_PORT_AFTER_H
#include <port_after.h>
#endif
#ifdef HAVE_NSS_H
DECLARE_TSS(gr_context, ent_context_t *, 1, NULL)
#define gr_context GET_TSS(gr_context)
#endif
#ifdef RFC2307BIS
static
char **_nss_ldap_no_members_return()
{
char **memret = malloc(sizeof(char *));
memret[0] = NULL;
return memret;
}
DECLARE_TSS_WITH_INIT(_nss_ldap_no_members, char **, _nss_ldap_no_members_return)
#define _nss_ldap_no_members GET_TSS(_nss_ldap_no_members)
#endif
void
_ldap_grp_init_tss_keys()
{
INIT_TSS_KEY(gr_context);
#ifdef RFC2307BIS
INIT_TSS_KEY(_nss_ldap_no_members);
#endif
}
static NSS_STATUS
_nss_ldap_parse_gr(LDAP * ld,
LDAPMessage * e,
ldap_state_t * pvt,
void *result, char *buffer, size_t buflen)
{
struct group *gr = (struct group *) result;
char *gid;
NSS_STATUS stat;
#ifdef RFC2307BIS
char **uid_mems, **dn_mems, **vals;
size_t uid_mems_c = 0, dn_mems_c = 0;
#endif /* RFC2307BIS */
stat =
_nss_ldap_assign_attrval(ld, e, AT(gidNumber), &gid, &buffer, &buflen);
if (stat != NSS_SUCCESS)
return stat;
gr->gr_gid = (*gid == '\0') ? GID_NOBODY : (gid_t) atol(gid);
stat =
_nss_ldap_getrdnvalue(ld, e, AT(cn), &gr->gr_name, &buffer, &buflen);
if (stat != NSS_SUCCESS)
return stat;
stat =
_nss_ldap_assign_userpassword(ld, e, AT(userPassword), &gr->gr_passwd,
&buffer, &buflen);
if (stat != NSS_SUCCESS)
return stat;
#ifndef RFC2307BIS
stat =
_nss_ldap_assign_attrvals(ld, e, AT(memberUid), NULL, &gr->gr_mem,
&buffer, &buflen, NULL);
if (stat != NSS_SUCCESS)
return stat;
#else
dn_mems = NULL;
vals = ldap_get_values(ld, e, AT(uniqueMember));
if (vals != NULL) {
char **mem_p, **valiter;
dn_mems_c = ldap_count_values(vals);
if (bytesleft(buffer, buflen, char *)<
(dn_mems_c + 1) * sizeof(char *)) {
ldap_value_free(vals);
return NSS_TRYAGAIN;
}
align(buffer, buflen, char *);
mem_p = dn_mems = (char **)buffer;
buffer += (dn_mems_c + 1) * sizeof(char *);
buflen -= (dn_mems_c + 1) * sizeof(char *);
for (valiter = vals; *valiter != NULL; valiter++) {
char *uid;
/*
* Remove optional UID (as in unique identifier) only for uniqueMember; member does not have UID
*/
if ((uid = strrchr(*valiter, '#')) != NULL) {
*uid = '\0';
}
stat = _nss_ldap_dn2uid(ld, *valiter, &uid, &buffer, &buflen);
switch (stat) {
case NSS_SUCCESS:
*mem_p = uid;
mem_p++;
break;
case NSS_TRYAGAIN:
ldap_value_free(vals);
return NSS_TRYAGAIN;
break;
case NSS_NOTFOUND:
default:
dn_mems_c--;
break;
}
}
ldap_value_free(vals);
}
stat =
_nss_ldap_assign_attrvals(ld, e, AT(memberUid), NULL, &uid_mems,
&buffer, &buflen, &uid_mems_c);
if (stat == NSS_TRYAGAIN)
return NSS_TRYAGAIN;
if (stat != NSS_SUCCESS)
uid_mems = NULL;
if (dn_mems == NULL) {
if (uid_mems == NULL)
gr->gr_mem = _nss_ldap_no_members;
else
gr->gr_mem = uid_mems;
} else {
if (uid_mems == NULL)
gr->gr_mem = dn_mems;
else {
if (bytesleft(buffer, buflen, char *)<
(dn_mems_c + uid_mems_c + 1) * sizeof(char *))
return NSS_TRYAGAIN;
align(buffer, buflen, char *);
gr->gr_mem = (char **)buffer;
buffer += (dn_mems_c + uid_mems_c + 1) * sizeof(char *);
buflen -= (dn_mems_c + uid_mems_c + 1) * sizeof(char *);
memcpy(gr->gr_mem, dn_mems, (dn_mems_c * sizeof(char *)));
memcpy(&gr->gr_mem[dn_mems_c], uid_mems,
(uid_mems_c * sizeof(char *)));
gr->gr_mem[dn_mems_c + uid_mems_c] = NULL;
}
}
#endif /* RFC2307BIS */
return NSS_SUCCESS;
}
#if defined(HAVE_NSSWITCH_H) || defined(HAVE_NSS_H) || defined(AIX)
#ifdef HAVE_NSS_H
NSS_STATUS
_nss_ldap_initgroups_dyn(const char *user, gid_t group,
long int *start, long int *size,
gid_t ** groupsp, long int limit,
int *errnop);
NSS_STATUS
_nss_ldap_initgroups(const char *user, gid_t group, long int *start,
long int *size, gid_t * groups, long int limit,
int *errnop)
{
return (_nss_ldap_initgroups_dyn(user, group, start, size, &groups, limit,
errnop));
}
#endif
#ifdef HAVE_NSSWITCH_H
static NSS_STATUS
_nss_ldap_getgroupsbymember_r(nss_backend_t * be, void *args)
#elif defined(HAVE_NSS_H)
NSS_STATUS
_nss_ldap_initgroups_dyn(const char *user, gid_t group, long int *start,
long int *size, gid_t ** groupsp, long int limit,
int *errnop)
#elif defined(AIX)
char *_nss_ldap_getgrset(char *user)
#endif
{
#ifdef HAVE_NSSWITCH_H
struct nss_groupsbymem *gbm = (struct nss_groupsbymem *) args;
#endif /* HAVE_NSSWITCH_H */
#ifdef RFC2307BIS
char *userdn = NULL;
const char *filter;
char filt[LDAP_FILT_MAXSIZ];
#endif /* RFC2307BIS */
ldap_args_t a;
NSS_STATUS stat;
LDAPMessage *res, *e;
#ifdef AIX
char *grplist = NULL;
size_t listlen = 0;
#endif /* AIX */
#ifdef HAVE_NSS_H
gid_t *groups = *groupsp;
#endif /* HAVE_NSS_H */
LA_INIT(a);
#if defined(HAVE_NSS_H) || defined(AIX)
LA_STRING(a) = user;
#else
LA_STRING(a) = gbm->username;
#endif /* HAVE_NSS_H || AIX */
LA_TYPE(a) = LA_TYPE_STRING;
_nss_ldap_enter();
#ifdef RFC2307BIS
/* initialize schema */
stat = _nss_ldap_init();
if (stat != NSS_SUCCESS) {
_nss_ldap_leave();
#ifndef AIX
return stat;
#else
return NULL;
#endif /* !AIX */
}
/* lookup the user's DN. XXX: import this filter from somewhere else */
snprintf(filt, LDAP_FILT_MAXSIZ, "(%s=%s)", AT(uid), "%s");
stat = _nss_ldap_search_s(&a, filt, LM_NONE, 1, &res);
if (stat == NSS_SUCCESS) {
e = _nss_ldap_first_entry(res);
if (e != NULL) {
userdn = _nss_ldap_get_dn(e);
}
ldap_msgfree(res);
}
if (userdn != NULL) {
LA_STRING2(a) = userdn;
LA_TYPE(a) = LA_TYPE_STRING_AND_STRING;
filter = _nss_ldap_filt_getgroupsbymemberanddn;
} else {
filter = _nss_ldap_filt_getgroupsbymember;
}
stat = _nss_ldap_search_s(&a, filter, LM_GROUP, LDAP_NO_LIMIT, &res);
if (userdn != NULL) {
#ifdef HAVE_LDAP_MEMFREE
ldap_memfree(userdn);
#else
free(userdn);
#endif /* HAVE_LDAP_MEMFREE */
}
#else
stat =
_nss_ldap_search_s(&a, _nss_ldap_filt_getgroupsbymember, LM_GROUP,
LDAP_NO_LIMIT, &res);
#endif /* RFC2307BIS */
if (stat != NSS_SUCCESS) {
_nss_ldap_leave();
#ifndef AIX
return stat;
#else
return NULL;
#endif
}
for (e = _nss_ldap_first_entry(res);
e != NULL; e = _nss_ldap_next_entry(e)) {
#ifdef AIX
char **values = _nss_ldap_get_values(e, AT(gidNumber));
if (values != NULL) {
size_t l = strlen(values[0]);
grplist = realloc(grplist, listlen + l + 2);
if (grplist == NULL) {
ldap_value_free(values);
ldap_msgfree(res);
_nss_ldap_leave();
return NULL;
}
memcpy(grplist + listlen, values[0], l);
grplist[listlen + l] = ',';
listlen += l + 1;
ldap_value_free(values);
}
#else
char **values = _nss_ldap_get_values(e, AT(gidNumber));
if (values != NULL) {
int i;
long int gid;
gid = strtol(values[0], (char **)NULL, 10);
ldap_value_free(values);
if ((gid == LONG_MIN || gid == LONG_MAX) && errno == ERANGE) {
continue;
}
#ifdef HAVE_NSSWITCH_H
/* weed out duplicates: is this really our responsibility? */
for (i = 0; i < gbm->numgids; i++) {
if (gbm->gid_array[i] == (gid_t) gid)
continue;
}
gbm->gid_array[gbm->numgids++] = (gid_t) gid;
if (gbm->numgids == gbm->maxgids) {
ldap_msgfree(res);
_nss_ldap_leave();
return NSS_SUCCESS;
}
#else
if (gid != group) {
if (*start == *size && limit <= 0) {
/* Need a bigger buffer */
groups = realloc(groups, 2 * *size * sizeof(*groups));
if (groups == NULL) {
ldap_msgfree(res);
*errnop = ENOMEM;
_nss_ldap_leave();
return NSS_TRYAGAIN;
}
*groupsp = groups;
*size *= 2;
}
/* weed out duplicates: is this really our responsibility? */
for (i = 0; i < *size; i++) {
if (groups[i] == gid)
continue;
}
groups[*start] = gid;
*start += 1;
if (*start == limit) {
ldap_msgfree(res);
_nss_ldap_leave();
return NSS_SUCCESS;
}
}
#endif /* HAVE_NSSWITCH_H */
}
#endif /* AIX */
}
ldap_msgfree(res);
_nss_ldap_leave();
#ifdef HAVE_NSS_H
return NSS_SUCCESS;
#elif defined(AIX)
/* Strip last comma and terminate the string */
if (grplist && listlen)
grplist[listlen - 1] = '\0';
return grplist;
#else
/* yes, NSS_NOTFOUND is the successful errno code. see nss_dbdefs.h */
return NSS_NOTFOUND;
#endif /* HAVE_NSS_H */
}
#endif /* HAVE_NSSWITCH_H || HAVE_NSS_H || AIX */
#ifdef HAVE_NSS_H
NSS_STATUS
_nss_ldap_getgrnam_r(const char *name,
struct group * result,
char *buffer, size_t buflen, int *errnop)
{
LOOKUP_NAME(name, result, buffer, buflen, errnop, _nss_ldap_filt_getgrnam,
LM_GROUP, _nss_ldap_parse_gr);
}
#elif defined(HAVE_NSSWITCH_H)
static NSS_STATUS
_nss_ldap_getgrnam_r(nss_backend_t * be, void *args)
{
LOOKUP_NAME(args, _nss_ldap_filt_getgrnam, LM_GROUP, _nss_ldap_parse_gr);
}
#endif
#ifdef HAVE_NSS_H
NSS_STATUS
_nss_ldap_getgrgid_r(gid_t gid,
struct group * result,
char *buffer, size_t buflen, int *errnop)
{
LOOKUP_NUMBER(gid, result, buffer, buflen, errnop, _nss_ldap_filt_getgrgid,
LM_GROUP, _nss_ldap_parse_gr);
}
#elif defined(HAVE_NSSWITCH_H)
static NSS_STATUS
_nss_ldap_getgrgid_r(nss_backend_t * be, void *args)
{
LOOKUP_NUMBER(args, key.gid, _nss_ldap_filt_getgrgid, LM_GROUP,
_nss_ldap_parse_gr);
}
#endif
#if defined(HAVE_NSS_H)
NSS_STATUS
_nss_ldap_setgrent(void)
{
LOOKUP_SETENT(gr_context);
}
#elif defined(HAVE_NSSWITCH_H)
static NSS_STATUS
_nss_ldap_setgrent_r(nss_backend_t * gr_context, void *args)
{
LOOKUP_SETENT(gr_context);
}
#endif
#if defined(HAVE_NSS_H)
NSS_STATUS
_nss_ldap_endgrent(void)
{
LOOKUP_ENDENT(gr_context);
}
#elif defined(HAVE_NSSWITCH_H)
static NSS_STATUS
_nss_ldap_endgrent_r(nss_backend_t * gr_context, void *args)
{
LOOKUP_ENDENT(gr_context);
}
#endif
#ifdef HAVE_NSS_H
NSS_STATUS
_nss_ldap_getgrent_r(struct group * result,
char *buffer, size_t buflen, int *errnop)
{
LOOKUP_GETENT(gr_context, result, buffer, buflen, errnop,
_nss_ldap_filt_getgrent, LM_GROUP, _nss_ldap_parse_gr);
}
#elif defined(HAVE_NSSWITCH_H)
static NSS_STATUS
_nss_ldap_getgrent_r(nss_backend_t * gr_context, void *args)
{
LOOKUP_GETENT(args, gr_context, _nss_ldap_filt_getgrent, LM_GROUP,
_nss_ldap_parse_gr);
}
#endif
#ifdef HAVE_NSSWITCH_H
static NSS_STATUS
_nss_ldap_group_destr(nss_backend_t * gr_context, void *args)
{
return _nss_ldap_default_destr(gr_context, args);
}
const static nss_backend_op_t group_ops[] = {
_nss_ldap_group_destr,
_nss_ldap_endgrent_r,
_nss_ldap_setgrent_r,
_nss_ldap_getgrent_r,
_nss_ldap_getgrnam_r,
_nss_ldap_getgrgid_r,
_nss_ldap_getgroupsbymember_r
};
nss_backend_t *
_nss_ldap_group_constr(const char *db_name,
const char *src_name, const char *cfg_args)
{
nss_ldap_backend_t *be;
if (!(be = (nss_ldap_backend_t *) malloc(sizeof(*be))))
return NULL;
be->ops = group_ops;
be->n_ops = sizeof(group_ops) / sizeof(nss_backend_op_t);
/* a NOOP at the moment */
if (_nss_ldap_default_constr(be) != NSS_SUCCESS)
return NULL;
return (nss_backend_t *) be;
}
#endif /* !HAVE_NSS_H */
#ifdef HAVE_IRS_H
#include "irs-grp.c"
#endif
syntax highlighted by Code2HTML, v. 0.9.1