getnetgrent.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <syslog.h>
#include "ldap_common.h"
/* netgroup attributes filters */
#define _N_NAME "cn"
#define _N_TRIPLE "nisnetgrouptriple"
#define _N_MEMBER "membernisnetgroup"
#define PRINT_VAL(a) (((a).argc == 0) || ((a).argv == NULL) || \
((a).argv[0] == NULL)) ? "*" : (a).argv[0]
#define ISWILD(a) ((a) == NULL)
#define GET_ARGV(a) (((a).argc == 0) || ((a).argv == NULL) || \
((a).argv[0] == NULL)) ? NULL : (a).argv[0]
#define ISNULL(a) (a == NULL ? "<NULL>" : a)
#define MAX_NETGR_NAME_LEN 256
#define MAX_DOMAIN_LEN 1024
#define MAX_TRIPLE_LEN (MAXHOSTNAMELEN + LOGNAME_MAX + \
MAX_DOMAIN_LEN + 5)
#define _F_GETNETGR_TRIPLE \
"(&(objectClass=nisNetGroup)" \
"(|(nisnetgrouptriple=(%s,%s,*))(nisnetgrouptriple=(%s,,*))" \
"(nisnetgrouptriple=(,%s,*))(nisnetgrouptriple=(,,*))))"
#define _F_GETNETGR_TRIPLE_SSD \
"(&(%%s)(|(nisnetgrouptriple=(%s,%s,*))(nisnetgrouptriple=(%s,,*))" \
"(nisnetgrouptriple=(,%s,*))(nisnetgrouptriple=(,,*))))"
#define _F_GETNETGR_TRIPLE_MACHINE \
"(&(objectClass=nisNetGroup)" \
"(|(nisnetgrouptriple=(%s,*,*))(nisnetgrouptriple=(,*,*))))"
#define _F_GETNETGR_TRIPLE_MACHINE_SSD \
"(&(%%s)(|(nisnetgrouptriple=(%s,*,*))(nisnetgrouptriple=(,*,*))))"
#define _F_GETNETGRENT \
"(&(objectClass=nisNetGroup)(nisnetgrouptriple=(%s,%s,%s)))"
#define _F_GETNETGRENT_SSD \
"(&(%%s)(nisnetgrouptriple=(%s,%s,%s)))"
/*
* Although the filter should include the test for (*,,*), this leads to
* an unindexed search. To support this, a plugin should be the directory
* server.
*/
#define _F_GETNETGR_TRIPLE_USER \
"(&(objectClass=nisNetGroup)(nisnetgrouptriple=(*,%s,*)))"
#define _F_GETNETGR_TRIPLE_USER_SSD \
"(&(%%s)(nisnetgrouptriple=(*,%s,*)))"
#define _F_GETMEMBERGRENT \
"(&(objectClass=nisNetGroup)(membernisnetgroup=%s))"
#define _F_GETMEMBERGRENT_SSD \
"(&(%%s)(membernisnetgroup=%s))"
#define _F_ISMEMBERGRENT \
"(&(objectClass=nisNetGroup)(cn=%s)(membernisnetgroup=%s))"
#define _F_ISMEMBERGRENT_SSD \
"(&(%%s)(cn=%s)(membernisnetgroup=%s))"
#define MAX_INNETGR_FILTER_LEN (2 * MAXHOSTNAMELEN + 2 * LOGNAME_MAX + 140)
#define MAX_GETMEM_FILTER_LEN (MAX_NETGR_NAME_LEN + 50)
#define MAX_ISMEM_FILTER_LEN (2 * MAX_NETGR_NAME_LEN + 56)
#define _F_GETMEMBER \
"(&(objectClass=nisNetGroup)(membernisnetgroup=%s))"
#define _F_GETMEMBER_SSD "(&(%%s)(membernisnetgroup=%s))"
#define _F_SETMEMBER "(&(objectClass=nisNetGroup)(cn=%s))"
#define _F_SETMEMBER_SSD "(&(%%s)(cn=%s))"
#define N_HASH 257
static const char *netgrent_attrs[] = {
_N_TRIPLE,
_N_MEMBER,
(char *)NULL
};
static const char *netgr_name_attrs[] = {
_N_NAME,
(char *)NULL
};
static const char *netgr_leaf_attrs[] = {
_N_NAME,
_N_TRIPLE,
(char *)NULL
};
static const char *netgr_node_attrs[] = {
_N_NAME,
_N_MEMBER,
(char *)NULL
};
typedef struct netgroup_name {
char *name;
struct netgroup_name *next;
struct netgroup_name *next_hash;
} netgroup_name_t;
typedef struct {
netgroup_name_t *hash_list[N_HASH];
netgroup_name_t *to_do;
netgroup_name_t *done;
} netgroup_table_t;
typedef struct {
ns_ldap_result_t *results;
ns_ldap_entry_t *entry;
char **attrs;
void *cookie;
char *netgroup;
netgroup_table_t tab;
} getnetgrent_cookie_t;
typedef struct {
struct nss_innetgr_args *ia;
const char *ssd_filter;
const char *netgrname;
const char *membername;
netgroup_table_t tab;
} innetgr_cookie_t;
typedef unsigned int hash_t;
static hash_t
get_hash(const char *s)
{
unsigned int sum = 0;
unsigned int i;
for (i = 0; s[i] != '\0'; i++)
sum += ((unsigned char *)s)[i];
return ((sum + i) % N_HASH);
}
static netgroup_name_t *
in_netgroup_table(const char *name, netgroup_table_t *tab)
{
hash_t h;
netgroup_name_t *ret;
if (tab == NULL || name == NULL || *name == '\0')
return (NULL);
h = get_hash(name);
ret = tab->hash_list[h];
while (ret != NULL) {
if (strcmp(name, ret->name) == 0)
break;
ret = ret->next_hash;
}
return (ret);
}
/*
* Adds a name to the netgroup table
*
* Returns
* 0 if successfully added or already present
* -1 if memory allocation error
*/
static int
add_netgroup_name(const char *name, netgroup_table_t *tab)
{
hash_t h;
netgroup_name_t *ng;
netgroup_name_t *ng_new;
if (tab == NULL || name == NULL || *name == '\0')
return (NULL);
h = get_hash(name);
ng = tab->hash_list[h];
while (ng != NULL) {
if (strcmp(name, ng->name) == 0)
break;
ng = ng->next_hash;
}
if (ng == NULL) {
ng_new = (netgroup_name_t *)
calloc(1, sizeof (netgroup_name_t));
if (ng_new == NULL)
return (-1);
ng_new->name = strdup(name);
if (ng_new->name == NULL) {
free(ng_new);
return (-1);
}
ng_new->next_hash = tab->hash_list[h];
tab->hash_list[h] = ng_new;
ng_new->next = tab->to_do;
tab->to_do = ng_new;
}
return (0);
}
static netgroup_name_t *
get_next_netgroup(netgroup_table_t *tab)
{
netgroup_name_t *ng;
if (tab == NULL)
return (NULL);
ng = tab->to_do;
if (ng != NULL) {
tab->to_do = ng->next;
ng->next = tab->done;
tab->done = ng;
}
return (ng);
}
static void
free_netgroup_table(netgroup_table_t *tab)
{
netgroup_name_t *ng, *next;
if (tab == NULL)
return;
for (ng = tab->to_do; ng != NULL; ng = next) {
if (ng->name != NULL)
free(ng->name);
next = ng->next;
free(ng);
}
for (ng = tab->done; ng != NULL; ng = next) {
if (ng->name != NULL)
free(ng->name);
next = ng->next;
free(ng);
}
(void) memset(tab, 0, sizeof (*tab));
}
/*
* domain comparing routine
* n1: See if n1 is n2 or an ancestor of it
* n2: (in string terms, n1 is a suffix of n2)
* Returns ZERO for success, -1 for failure.
*/
static int
domcmp(const char *n1, const char *n2)
{
#define PASS 0
#define FAIL -1
size_t l1, l2;
if ((n1 == NULL) || (n2 == NULL))
return (FAIL);
l1 = strlen(n1);
l2 = strlen(n2);
/* Turn a blind eye to the presence or absence of trailing periods */
if (l1 != 0 && n1[l1 - 1] == '.') {
--l1;
}
if (l2 != 0 && n2[l2 - 1] == '.') {
--l2;
}
if (l1 > l2) { /* Can't be a suffix */
return (FAIL);
} else if (l1 == 0) { /* Trivially a suffix; */
/* (do we want this case?) */
return (PASS);
}
/* So 0 < l1 <= l2 */
if (l1 < l2 && n2[l2 - l1 - 1] != '.') {
return (FAIL);
}
if (strncasecmp(n1, &n2[l2 - l1], l1) == 0) {
return (PASS);
} else {
return (FAIL);
}
}
static int
split_triple(char *triple, char **hostname, char **username, char **domain)
{
int i, syntax_err;
char *splittriple[3];
char *p = triple;
#ifdef DEBUG
(void) fprintf(stdout, "\n[getnetgrent.c: split_triple]\n");
#endif /* DEBUG */
if (triple == NULL)
return (-1);
p++;
syntax_err = 0;
for (i = 0; i < 3; i++) {
char *start;
char *limit;
const char *terminators = ",) \t";
if (i == 2) {
/* Don't allow comma */
terminators++;
}
while (isspace(*p)) {
p++;
}
start = p;
limit = strpbrk(start, terminators);
if (limit == 0) {
syntax_err++;
break;
}
p = limit;
while (isspace(*p)) {
p++;
}
if (*p == terminators[0]) {
/*
* Successfully parsed this name and
* the separator after it (comma or
* right paren); leave p ready for
* next parse.
*/
p++;
if (start == limit) {
/* Wildcard */
splittriple[i] = NULL;
} else {
*limit = '\0';
splittriple[i] = start;
}
} else {
syntax_err++;
break;
}
}
if (syntax_err != 0)
return (-1);
*hostname = splittriple[0];
*username = splittriple[1];
*domain = splittriple[2];
return (0);
}
/*
* check the domain part of the triples.
* -1 = fails to match, 0 = match
*/
static int
match_triple_entry(struct nss_innetgr_args *ia, const ns_ldap_entry_t *entry)
{
int ndomains;
char **pdomains;
int nhost;
char **phost;
int nusers;
char **pusers;
char **attr;
char triple[MAX_TRIPLE_LEN];
char *tuser, *thost, *tdomain;
int i;
nhost = ia->arg[NSS_NETGR_MACHINE].argc;
phost = (char **)ia->arg[NSS_NETGR_MACHINE].argv;
if (phost == NULL || *phost == NULL)
nhost = 0;
nusers = ia->arg[NSS_NETGR_USER].argc;
pusers = (char **)ia->arg[NSS_NETGR_USER].argv;
if (pusers == NULL || *pusers == NULL)
nusers = 0;
ndomains = ia->arg[NSS_NETGR_DOMAIN].argc;
pdomains = (char **)ia->arg[NSS_NETGR_DOMAIN].argv;
if (pdomains == NULL || *pdomains == NULL)
ndomains = 0;
attr = __ns_ldap_getAttr(entry, _N_TRIPLE);
if (attr == NULL || *attr == NULL)
return (0);
for (; *attr; attr++) {
if (strlcpy(triple, *attr, sizeof (triple)) >= sizeof (triple))
continue;
if (split_triple(triple, &thost, &tuser, &tdomain) != 0)
continue;
if (thost != NULL && *thost != '\0' && nhost != 0) {
for (i = 0; i < nhost; i++)
if (strcasecmp(thost, phost[i]) == 0)
break;
if (i == nhost)
continue;
}
if (tuser != NULL && *tuser != '\0' && nusers != 0) {
for (i = 0; i < nusers; i++)
if (strcmp(tuser, pusers[i]) == 0)
break;
if (i == nusers)
continue;
}
if (tdomain != NULL && *tdomain != '\0' && ndomains != 0) {
for (i = 0; i < ndomains; i++)
if (domcmp(tdomain, pdomains[i]) == 0)
break;
if (i == ndomains)
continue;
}
return (1);
}
return (0);
}
static int
match_triple(struct nss_innetgr_args *ia, ns_ldap_result_t *result)
{
ns_ldap_entry_t *entry;
for (entry = result->entry; entry != NULL; entry = entry->next)
if (match_triple_entry(ia, entry) == 1)
return (1);
return (0);
}
static int
add_netgroup_member_entry(ns_ldap_entry_t *entry, netgroup_table_t *tab)
{
char **attrs;
char **a;
attrs = __ns_ldap_getAttr(entry, _N_MEMBER);
if (attrs == NULL || *attrs == NULL)
return (0);
for (a = attrs; *a != NULL; a++) {}
do {
a--;
if (add_netgroup_name(*a, tab) != 0)
return (-1);
} while (a > attrs);
return (0);
}
static int
add_netgroup_member(ns_ldap_result_t *result, netgroup_table_t *tab)
{
ns_ldap_entry_t *entry;
int ret = 0;
for (entry = result->entry; entry != NULL; entry = entry->next) {
ret = add_netgroup_member_entry(entry, tab);
if (ret != 0)
break;
}
return (ret);
}
/*
* top_down_search checks only checks the netgroup specified in netgrname
*/
static nss_status_t
top_down_search(struct nss_innetgr_args *ia, char *netgrname)
{
char searchfilter[SEARCHFILTERLEN];
char name[SEARCHFILTERLEN];
char userdata[SEARCHFILTERLEN];
ns_ldap_result_t *result = NULL;
ns_ldap_error_t *error = NULL;
int rc;
void *cookie = NULL;
nss_status_t status = NSS_NOTFOUND;
netgroup_table_t tab;
netgroup_name_t *ng;
int ret;
(void) memset(&tab, 0, sizeof (tab));
if (add_netgroup_name(netgrname, &tab) != 0)
return ((nss_status_t)NSS_NOTFOUND);
while ((ng = get_next_netgroup(&tab)) != NULL) {
if (_ldap_filter_name(name, ng->name, sizeof (name)) != 0)
break;
ret = snprintf(searchfilter, sizeof (searchfilter), _F_SETMEMBER,
name);
if (ret >= sizeof (searchfilter) || ret < 0)
break;
ret = snprintf(userdata, sizeof (userdata), _F_SETMEMBER_SSD, name);
if (ret >= sizeof (userdata) || ret < 0)
break;
rc = __ns_ldap_firstEntry(_NETGROUP, searchfilter,
_merge_SSD_filter, netgrent_attrs, NULL, 0, &cookie, &result,
&error, userdata);
(void) __ns_ldap_freeError(&error);
while (rc == NS_LDAP_SUCCESS && result != NULL) {
if (match_triple(ia, result) == 1) {
/* We found a match */
ia->status = NSS_NETGR_FOUND;
status = NSS_SUCCESS;
break;
}
rc = add_netgroup_member(result, &tab);
(void) __ns_ldap_freeResult(&result);
if (rc != NS_LDAP_SUCCESS)
break;
rc = __ns_ldap_nextEntry(cookie, &result, &error);
(void) __ns_ldap_freeError(&error);
}
(void) __ns_ldap_freeResult(&result);
(void) __ns_ldap_endEntry(&cookie, &error);
(void) __ns_ldap_freeError(&error);
if (status == NSS_SUCCESS ||
(rc != NS_LDAP_SUCCESS && rc != NS_LDAP_NOTFOUND))
break;
}
(void) __ns_ldap_freeResult(&result);
(void) __ns_ldap_endEntry(&cookie, &error);
(void) __ns_ldap_freeError(&error);
free_netgroup_table(&tab);
return (status);
}
static int
innetgr_SSD_filter(const ns_ldap_search_desc_t *desc, char **realfilter,
const void *userdata)
{
const innetgr_cookie_t *cookie = (innetgr_cookie_t *)userdata;
return (_merge_SSD_filter(desc, realfilter, cookie->ssd_filter));
}
static int process_innetgr_node(const ns_ldap_entry_t *entry,
const void *userdata);
/* return 1 when done, 0 otherwise */
static int
check_parent(const char *gr_name, innetgr_cookie_t *cookie)
{
ns_ldap_result_t *result = NULL;
ns_ldap_error_t *error = NULL;
char searchfilter[MAX_GETMEM_FILTER_LEN];
char name[MAX_GETMEM_FILTER_LEN];
char ssd_filter[MAX_GETMEM_FILTER_LEN];
const char *ssd_filter_sav = cookie->ssd_filter;
int ret;
#ifdef DEBUG
(void) fprintf(stdout, "\n[getnetgrent.c: check_parent:%s]\n", gr_name);
#endif /* DEBUG */
if (_ldap_filter_name(name, gr_name, sizeof (name)) != 0)
return (0);
ret = snprintf(searchfilter, sizeof (searchfilter),
_F_GETMEMBERGRENT, name);
if (ret >= sizeof (searchfilter) || ret < 0)
return (0);
ret = snprintf(ssd_filter, sizeof (ssd_filter),
_F_GETMEMBERGRENT_SSD, name);
if (ret >= sizeof (ssd_filter) || ret < 0)
return (0);
cookie->ssd_filter = ssd_filter;
cookie->membername = gr_name;
(void) __ns_ldap_list(_NETGROUP, searchfilter, innetgr_SSD_filter,
netgr_node_attrs, NULL, 0, &result, &error,
process_innetgr_node, cookie);
cookie->ssd_filter = ssd_filter_sav;
(void) __ns_ldap_freeResult(&result);
(void) __ns_ldap_freeError(&error);
return (cookie->ia->status == NSS_NETGR_NO ? 0 : 1);
}
/* Use the server's matching rule if not a case exact match */
static int
server_match(innetgr_cookie_t *cookie)
{
ns_ldap_result_t *result = NULL;
ns_ldap_error_t *error = NULL;
char searchfilter[MAX_ISMEM_FILTER_LEN];
char netgrname[MAX_ISMEM_FILTER_LEN];
char membername[MAX_ISMEM_FILTER_LEN];
char ssd_filter[MAX_ISMEM_FILTER_LEN];
const char *ssd_filter_sav = cookie->ssd_filter;
int rc;
int ret;
if (_ldap_filter_name(netgrname, cookie->netgrname,
sizeof (netgrname)) != 0)
return (0);
if (_ldap_filter_name(membername, cookie->membername,
sizeof (membername)) != 0)
return (0);
ret = snprintf(searchfilter, sizeof (searchfilter), _F_ISMEMBERGRENT,
netgrname, membername);
if (ret >= sizeof (searchfilter) || ret < 0)
return (0);
ret = snprintf(ssd_filter, sizeof (ssd_filter), _F_ISMEMBERGRENT_SSD,
netgrname, membername);
if (ret >= sizeof (ssd_filter) || ret < 0)
return (0);
cookie->ssd_filter = ssd_filter;
rc = __ns_ldap_list(_NETGROUP, searchfilter, innetgr_SSD_filter,
netgr_name_attrs, NULL, 0, &result, &error,
NULL, &cookie);
(void) __ns_ldap_freeResult(&result);
(void) __ns_ldap_freeError(&error);
cookie->ssd_filter = ssd_filter_sav;
return (rc == NS_LDAP_SUCCESS);
}
static int
process_innetgr_node(const ns_ldap_entry_t *entry, const void *userdata)
{
innetgr_cookie_t *cookie = (innetgr_cookie_t *)userdata;
char **a, **attr;
attr = __ns_ldap_getAttr(entry, _N_NAME);
if (attr == NULL)
return (NS_LDAP_CB_NEXT);
for (a = attr; *a; a++) {
#ifdef DEBUG
(void) fprintf(stdout, "\n[getnetgrent.c: process_innetgr_node:%s]\n",
*a);
#endif /* DEBUG */
if (strcasecmp(*a, cookie->netgrname) == 0) {
if (strcmp(*a, cookie->netgrname) == 0 ||
server_match(cookie)) {
cookie->ia->status = NSS_NETGR_FOUND;
return (NS_LDAP_CB_DONE);
}
}
}
for (a = attr; *a; a++) {
/* check if we have already visited this node */
if (in_netgroup_table(*a, &cookie->tab) != NULL)
continue;
if (add_netgroup_name(*a, &cookie->tab) != 0) {
cookie->ia->status = NSS_NETGR_NOMEM;
return (NS_LDAP_CB_DONE);
}
if (check_parent(*a, cookie) == 1)
return (NS_LDAP_CB_DONE);
}
return (NS_LDAP_CB_NEXT);
}
static int
process_innetgr_leaf(const ns_ldap_entry_t *entry, const void *userdata)
{
innetgr_cookie_t *cookie = (innetgr_cookie_t *)userdata;
/* Check to see if this entry matches the triple */
if (match_triple_entry(cookie->ia, entry) != 1)
return (NS_LDAP_CB_NEXT);
return (process_innetgr_node(entry, userdata));
}
/*
* __netgr_in checks only checks the netgroup specified in ngroup
*/
static nss_status_t
__netgr_in(void *a, char *netgrname)
{
struct nss_innetgr_args *ia = (struct nss_innetgr_args *)a;
char searchfilter[MAX_INNETGR_FILTER_LEN];
char ssd_filter[MAX_INNETGR_FILTER_LEN];
char mach[MAX_INNETGR_FILTER_LEN];
char user[MAX_INNETGR_FILTER_LEN];
ns_ldap_result_t *result = NULL;
ns_ldap_error_t *error = NULL;
int rc;
nss_status_t status = NSS_NOTFOUND;
innetgr_cookie_t cookie = {NULL, NULL, NULL};
int user_wild, mach_wild;
int ret;
#ifdef DEBUG
(void) fprintf(stdout, "\n[getnetgrent.c: netgr_in]\n");
(void) fprintf(stdout, "\tmachine: argc[%d]='%s' user: "
"argc[%d]='%s',\n\tdomain:argc[%d]='%s' "
"netgroup: argc[%d]='%s'\n",
NSS_NETGR_MACHINE,
PRINT_VAL(ia->arg[NSS_NETGR_MACHINE]),
NSS_NETGR_USER,
PRINT_VAL(ia->arg[NSS_NETGR_USER]),
NSS_NETGR_DOMAIN,
PRINT_VAL(ia->arg[NSS_NETGR_DOMAIN]),
NSS_NETGR_N,
PRINT_VAL(ia->arg[NSS_NETGR_N]));
(void) fprintf(stdout, "\tgroups='%s'\n", netgrname);
#endif /* DEBUG */
ia->status = NSS_NETGR_NO;
if (netgrname == NULL)
return (status);
mach_wild = (ia->arg[NSS_NETGR_MACHINE].argc == 0) ||
(ia->arg[NSS_NETGR_MACHINE].argv == NULL) ||
(ia->arg[NSS_NETGR_MACHINE].argv[0] == NULL);
user_wild = (ia->arg[NSS_NETGR_USER].argc == 0) ||
(ia->arg[NSS_NETGR_USER].argv == NULL) ||
(ia->arg[NSS_NETGR_USER].argv[0] == NULL);
if (!mach_wild && _ldap_filter_name(mach,
ia->arg[NSS_NETGR_MACHINE].argv[0], sizeof (mach)) != 0)
return ((nss_status_t)NSS_NOTFOUND);
if (!user_wild && _ldap_filter_name(user,
ia->arg[NSS_NETGR_USER].argv[0], sizeof (user)) != 0)
return ((nss_status_t)NSS_NOTFOUND);
if (!mach_wild && !user_wild) {
ret = snprintf(searchfilter, sizeof (searchfilter),
_F_GETNETGR_TRIPLE, mach, user, mach, user);
if (ret >= sizeof (searchfilter) || ret < 0)
return ((nss_status_t)NSS_NOTFOUND);
ret = snprintf(ssd_filter, sizeof (ssd_filter),
_F_GETNETGR_TRIPLE_SSD, mach, user, mach, user);
if (ret >= sizeof (ssd_filter) || ret < 0)
return ((nss_status_t)NSS_NOTFOUND);
} else if (!mach_wild && user_wild) {
ret = snprintf(searchfilter, sizeof (searchfilter),
_F_GETNETGR_TRIPLE_MACHINE, mach);
if (ret >= sizeof (searchfilter) || ret < 0)
return ((nss_status_t)NSS_NOTFOUND);
ret = snprintf(ssd_filter, sizeof (ssd_filter),
_F_GETNETGR_TRIPLE_MACHINE_SSD, mach);
if (ret >= sizeof (ssd_filter) || ret < 0)
return ((nss_status_t)NSS_NOTFOUND);
} else if (mach_wild && !user_wild) {
ret = snprintf(searchfilter, sizeof (searchfilter),
_F_GETNETGR_TRIPLE_USER, user);
if (ret >= sizeof (searchfilter) || ret < 0)
return ((nss_status_t)NSS_NOTFOUND);
ret = snprintf(ssd_filter, sizeof (ssd_filter),
_F_GETNETGR_TRIPLE_USER_SSD, user);
if (ret >= sizeof (ssd_filter) || ret < 0)
return ((nss_status_t)NSS_NOTFOUND);
} else {
return (top_down_search(ia, netgrname));
}
cookie.ia = ia;
cookie.ssd_filter = ssd_filter;
cookie.netgrname = netgrname;
(void) memset(&cookie.tab, 0, sizeof (cookie.tab));
rc = __ns_ldap_list(_NETGROUP, searchfilter, innetgr_SSD_filter,
netgr_leaf_attrs, NULL, 0, &result, &error,
process_innetgr_leaf, &cookie);
status = switch_err(rc, error);
(void) __ns_ldap_freeResult(&result);
(void) __ns_ldap_freeError(&error);
free_netgroup_table(&cookie.tab);
return (status);
}
/*ARGSUSED0*/
static nss_status_t
netgr_in(ldap_backend_ptr be, void *a)
{
struct nss_innetgr_args *ia = (struct nss_innetgr_args *)a;
int i;
nss_status_t rc = (nss_status_t)NSS_NOTFOUND;
ia->status = NSS_NETGR_NO;
for (i = 0; i < ia->groups.argc; i++) {
rc = __netgr_in(a, ia->groups.argv[i]);
if (ia->status == NSS_NETGR_FOUND)
return (NSS_SUCCESS);
}
return (rc);
}
/*
*
*/
static nss_status_t
getnetgr_ldap_setent(ldap_backend_ptr be, void *a)
{
const char *netgroup = (const char *) a;
getnetgrent_cookie_t *cookie;
#ifdef DEBUG
(void) fprintf(stdout, "\n[getnetgrent.c: getnetgr_ldap_setent]\n");
#endif /* DEBUG */
cookie = (getnetgrent_cookie_t *)be->netgroup_cookie;
if (cookie != NULL && cookie->netgroup != NULL) {
/* is this another set on the same netgroup */
if (strcmp(cookie->netgroup, netgroup) == 0)
return ((nss_status_t)NSS_SUCCESS);
}
return (NSS_NOTFOUND);
}
static void
free_getnetgrent_cookie(getnetgrent_cookie_t **cookie)
{
ns_ldap_error_t *error = NULL;
getnetgrent_cookie_t *p = *cookie;
#ifdef DEBUG
(void) fprintf(stdout, "\n[getnetgrent.c: free_getnetgrent_cookie]\n");
#endif /* DEBUG */
if (p == NULL)
return;
(void) __ns_ldap_freeResult(&p->results);
(void) __ns_ldap_endEntry(&p->cookie, &error);
(void) __ns_ldap_freeError(&error);
free_netgroup_table(&p->tab);
free(p->netgroup);
free(p);
*cookie = NULL;
}
/*ARGSUSED1*/
static nss_status_t
getnetgr_ldap_endent(ldap_backend_ptr be, void *a)
{
#ifdef DEBUG
(void) fprintf(stdout, "\n[getnetgrent.c: getnetgr_ldap_endent]\n");
#endif /* DEBUG */
free_getnetgrent_cookie((getnetgrent_cookie_t **)&be->netgroup_cookie);
return ((nss_status_t)NSS_NOTFOUND);
}
/*ARGSUSED1*/
static nss_status_t
getnetgr_ldap_destr(ldap_backend_ptr be, void *a)
{
#ifdef DEBUG
(void) fprintf(stdout, "\n[getnetgrent.c: getnetgr_ldap_destr]\n");
#endif /* DEBUG */
free_getnetgrent_cookie((getnetgrent_cookie_t **)&be->netgroup_cookie);
free(be);
return ((nss_status_t)NSS_NOTFOUND);
}
static nss_status_t
getnetgr_ldap_getent(ldap_backend_ptr be, void *a)
{
struct nss_getnetgrent_args *args;
getnetgrent_cookie_t *p;
char searchfilter[SEARCHFILTERLEN];
char userdata[SEARCHFILTERLEN];
char name[SEARCHFILTERLEN];
int rc;
void *cookie = NULL;
ns_ldap_result_t *result = NULL;
ns_ldap_error_t *error = NULL;
char **attrs;
char *hostname, *username, *domain;
char *buffer;
nss_status_t status = NSS_SUCCESS;
netgroup_name_t *ng;
int ret;
#ifdef DEBUG
(void) fprintf(stdout, "\n[getnetgrent.c: getnetgr_ldap_getent]\n");
#endif /* DEBUG */
args = (struct nss_getnetgrent_args *)a;
args->status = NSS_NETGR_NO;
p = (getnetgrent_cookie_t *)be->netgroup_cookie;
if (p == NULL)
return ((nss_status_t)NSS_SUCCESS);
for (;;) {
while (p->cookie == NULL) {
ng = get_next_netgroup(&p->tab);
if (ng == NULL) /* no more */
break;
if (_ldap_filter_name(name, ng->name, sizeof (name)) != 0)
break;
ret = snprintf(searchfilter, sizeof (searchfilter),
_F_SETMEMBER, name);
if (ret >= sizeof (searchfilter) || ret < 0)
break;
ret = snprintf(userdata, sizeof (userdata), _F_SETMEMBER_SSD,
name);
if (ret >= sizeof (userdata) || ret < 0)
break;
result = NULL;
rc = __ns_ldap_firstEntry(_NETGROUP, searchfilter,
_merge_SSD_filter, netgrent_attrs, NULL, 0, &cookie,
&result, &error, userdata);
(void) __ns_ldap_freeError(&error);
if (rc == NS_LDAP_SUCCESS && result != NULL) {
p->cookie = cookie;
p->results = result;
break;
}
(void) __ns_ldap_freeResult(&result);
(void) __ns_ldap_endEntry(&cookie, &error);
(void) __ns_ldap_freeError(&error);
}
if (p->cookie == NULL)
break;
if (p->results == NULL) {
result = NULL;
rc = __ns_ldap_nextEntry(p->cookie, &result, &error);
(void) __ns_ldap_freeError(&error);
if (rc == NS_LDAP_SUCCESS && result != NULL)
p->results = result;
else {
(void) __ns_ldap_freeResult(&result);
(void) __ns_ldap_endEntry(&p->cookie, &error);
(void) __ns_ldap_freeError(&error);
p->cookie = NULL;
}
}
if (p->results == NULL)
continue;
if (p->entry == NULL)
p->entry = p->results->entry;
if (p->entry == NULL)
continue;
if (p->attrs == NULL) {
attrs = __ns_ldap_getAttr(p->entry, _N_TRIPLE);
if (attrs != NULL && *attrs != NULL)
p->attrs = attrs;
}
if (p->attrs != NULL) {
attrs = p->attrs;
buffer = args->buffer;
if (strlcpy(buffer, *attrs, args->buflen) >= args->buflen) {
status = NSS_STR_PARSE_ERANGE;
break;
}
rc = split_triple(buffer, &hostname, &username, &domain);
attrs++;
if (attrs != NULL && *attrs != NULL)
p->attrs = attrs;
else
p->attrs = NULL;
if (rc == 0) {
args->retp[NSS_NETGR_MACHINE] = hostname;
args->retp[NSS_NETGR_USER] = username;
args->retp[NSS_NETGR_DOMAIN] = domain;
args->status = NSS_NETGR_FOUND;
if (p->attrs != NULL)
break;
}
}
if (p->attrs == NULL) {
rc = add_netgroup_member_entry(p->entry, &p->tab);
if (rc != 0) {
args->status = NSS_NETGR_NO;
break;
}
p->entry = p->entry->next;
if (p->entry == NULL)
(void) __ns_ldap_freeResult(&p->results);
if (args->status == NSS_NETGR_FOUND)
break;
}
}
return (status);
}
static ldap_backend_op_t getnetgroup_ops[] = {
getnetgr_ldap_destr,
getnetgr_ldap_endent,
getnetgr_ldap_setent,
getnetgr_ldap_getent,
};
/*
*
*/
static nss_status_t
netgr_set(ldap_backend_ptr be, void *a)
{
struct nss_setnetgrent_args *args =
(struct nss_setnetgrent_args *)a;
ldap_backend_ptr get_be;
getnetgrent_cookie_t *p;
#ifdef DEBUG
(void) fprintf(stdout, "\n[getnetgrent.c: netgr_set]\n");
(void) fprintf(stdout,
"\targs->netgroup: %s\n", ISNULL(args->netgroup));
#endif /* DEBUG */
if (args->netgroup == NULL)
return ((nss_status_t)NSS_NOTFOUND);
free_getnetgrent_cookie((getnetgrent_cookie_t **)&be->netgroup_cookie);
p = (getnetgrent_cookie_t *)calloc(1, sizeof (getnetgrent_cookie_t));
if (p == NULL)
return ((nss_status_t)NSS_NOTFOUND);
p->netgroup = strdup(args->netgroup);
if (p->netgroup == NULL) {
free(p);
return ((nss_status_t)NSS_NOTFOUND);
}
if (add_netgroup_name(args->netgroup, &p->tab) == -1) {
free_getnetgrent_cookie(&p);
return ((nss_status_t)NSS_NOTFOUND);
}
/* now allocate and return iteration backend structure */
if ((get_be = (ldap_backend_ptr)malloc(sizeof (*get_be))) == NULL)
return (NSS_UNAVAIL);
get_be->ops = getnetgroup_ops;
get_be->nops = sizeof (getnetgroup_ops) / sizeof (getnetgroup_ops[0]);
get_be->tablename = NULL;
get_be->attrs = netgrent_attrs;
get_be->result = NULL;
get_be->ldapobj2ent = NULL;
get_be->setcalled = 1;
get_be->filter = NULL;
get_be->toglue = NULL;
get_be->enumcookie = NULL;
get_be->netgroup_cookie = p;
args->iterator = (nss_backend_t *)get_be;
(void) __ns_ldap_freeResult(&be->result);
return (NSS_SUCCESS);
}
/*ARGSUSED1*/
static nss_status_t
netgr_ldap_destr(ldap_backend_ptr be, void *a)
{
#ifdef DEBUG
(void) fprintf(stdout, "\n[getnetgrent.c: netgr_ldap_destr]\n");
#endif /* DEBUG */
(void) _clean_ldap_backend(be);
return ((nss_status_t)NSS_NOTFOUND);
}
static ldap_backend_op_t netgroup_ops[] = {
netgr_ldap_destr,
0,
0,
0,
netgr_in, /* innetgr() */
netgr_set /* setnetgrent() */
};
/*
* _nss_ldap_netgroup_constr is where life begins. This function calls the
* generic ldap constructor function to define and build the abstract data
* types required to support ldap operations.
*/
/*ARGSUSED0*/
nss_backend_t *
_nss_ldap_netgroup_constr(const char *dummy1, const char *dummy2,
const char *dummy3)
{
#ifdef DEBUG
(void) fprintf(stdout,
"\n[getnetgrent.c: _nss_ldap_netgroup_constr]\n");
#endif /* DEBUG */
return ((nss_backend_t *)_nss_ldap_constr(netgroup_ops,
sizeof (netgroup_ops)/sizeof (netgroup_ops[0]), _NETGROUP,
netgrent_attrs, NULL));
}