/* Copyright (c) 2004 Michael Bushkov */ /* * Copyright (C) 1997-2003 Luke Howard. This file is part of the nss_ldap library. Contributed by Luke Howard, , 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 #endif #ifdef HAVE_THREAD_H #include #elif defined(HAVE_PTHREAD_H) #include #endif #include #include #include #include #include #include #ifdef HAVE_LBER_H #include #endif #ifdef HAVE_LDAP_H #include #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 #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