Arthur de Jong

Open Source / Free Software developer

summaryrefslogtreecommitdiffstats
path: root/nslcd/netgroup.c
diff options
context:
space:
mode:
Diffstat (limited to 'nslcd/netgroup.c')
-rw-r--r--nslcd/netgroup.c354
1 files changed, 354 insertions, 0 deletions
diff --git a/nslcd/netgroup.c b/nslcd/netgroup.c
new file mode 100644
index 0000000..e79657d
--- /dev/null
+++ b/nslcd/netgroup.c
@@ -0,0 +1,354 @@
+/*
+ netgroup.c - netgroup lookup routines
+ This file was part of the nss_ldap library (as ldap-netgrp.c)
+ which has been forked into the nss-ldapd library.
+ This file also contains code that is taken from the GNU C
+ Library (nss/nss_files/files-netgrp.c).
+
+ Copyright (C) 1996, 1997, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-2005 Luke Howard
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This 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.
+
+ This 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 this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <string.h>
+#include <assert.h>
+#if defined(HAVE_THREAD_H)
+#include <thread.h>
+#elif defined(HAVE_PTHREAD_H)
+#include <pthread.h>
+#endif
+#ifdef HAVE_LBER_H
+#include <lber.h>
+#endif
+#ifdef HAVE_LDAP_H
+#include <ldap.h>
+#endif
+
+#include "ldap-nss.h"
+#include "util.h"
+#include "common.h"
+#include "log.h"
+
+/* A netgroup can consist of names of other netgroups. We have to
+ track which netgroups were read and which still have to be read. */
+
+/* Dataset for iterating netgroups. */
+struct __netgrent
+{
+ enum
+ { triple_val, group_val }
+ type;
+
+ union
+ {
+ struct
+ {
+ const char *host;
+ const char *user;
+ const char *domain;
+ }
+ triple;
+
+ const char *group;
+ }
+ val;
+
+ /* Room for the data kept between the calls to the netgroup
+ functions. We must avoid global variables. */
+ char *data;
+ size_t data_size;
+ char *cursor;
+ int first;
+
+ struct name_list *known_groups;
+ struct name_list *needed_groups;
+};
+
+/*
+ * I (Luke Howard) pulled the following macro (EXPAND), functions
+ * (strip_whitespace and _nss_netgroup_parseline) and structures
+ * (name_list and __netgrent) from glibc-2.2.x. _nss_netgroup_parseline
+ * became _nss_ldap_parse_netgr after some modification.
+ *
+ * The rest of the code is modeled on various other _nss_ldap functions.
+ */
+
+#define EXPAND(needed) \
+ do \
+ { \
+ size_t old_cursor = result->cursor - result->data; \
+ \
+ result->data_size += 512 > 2 * needed ? 512 : 2 * needed; \
+ result->data = realloc (result->data, result->data_size); \
+ \
+ if (result->data == NULL) \
+ { \
+ stat = NSS_STATUS_UNAVAIL; \
+ goto out; \
+ } \
+ \
+ result->cursor = result->data + old_cursor; \
+ } \
+ while (0)
+
+static char *
+strip_whitespace (char *str)
+{
+ char *cp = str;
+
+ /* Skip leading spaces. */
+ while (isspace ((int) *cp))
+ cp++;
+
+ str = cp;
+ while (*cp != '\0' && !isspace ((int) *cp))
+ cp++;
+
+ /* Null-terminate, stripping off any trailing spaces. */
+ *cp = '\0';
+
+ return *str == '\0' ? NULL : str;
+}
+
+static enum nss_status
+_nss_ldap_parse_netgr (void *vresultp, char *buffer, size_t buflen)
+{
+ struct __netgrent *result = (struct __netgrent *) vresultp;
+ char *cp = result->cursor;
+ char *user, *host, *domain;
+
+ /* The netgroup either doesn't exist or is empty. */
+ if (cp == NULL)
+ return NSS_STATUS_RETURN;
+
+ /* First skip leading spaces. */
+ while (isspace ((int) *cp))
+ ++cp;
+
+ if (*cp != '(')
+ {
+ /* We have a list of other netgroups. */
+ char *name = cp;
+
+ while (*cp != '\0' && !isspace ((int) *cp))
+ ++cp;
+
+ if (name != cp)
+ {
+ /* It is another netgroup name. */
+ int last = *cp == '\0';
+
+ result->type = group_val;
+ result->val.group = name;
+ *cp = '\0';
+ if (!last)
+ ++cp;
+ result->cursor = cp;
+ result->first = 0;
+
+ return NSS_STATUS_SUCCESS;
+ }
+ return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
+ }
+
+ /* Match host name. */
+ host = ++cp;
+ while (*cp != ',')
+ if (*cp++ == '\0')
+ return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
+
+ /* Match user name. */
+ user = ++cp;
+ while (*cp != ',')
+ if (*cp++ == '\0')
+ return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
+
+ /* Match domain name. */
+ domain = ++cp;
+ while (*cp != ')')
+ if (*cp++ == '\0')
+ return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
+ ++cp;
+
+ /* When we got here we have found an entry. Before we can copy it
+ to the private buffer we have to make sure it is big enough. */
+ if (cp - host > buflen)
+ return NSS_STATUS_TRYAGAIN;
+
+ strncpy (buffer, host, cp - host);
+ result->type = triple_val;
+
+ buffer[(user - host) - 1] = '\0';
+ result->val.triple.host = strip_whitespace (buffer);
+
+ buffer[(domain - host) - 1] = '\0';
+ result->val.triple.user = strip_whitespace (buffer + (user - host));
+
+ buffer[(cp - host) - 1] = '\0';
+ result->val.triple.domain = strip_whitespace (buffer + (domain - host));
+
+ /* Remember where we stopped reading. */
+ result->cursor = cp;
+ result->first = 0;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+_nss_ldap_load_netgr (LDAPMessage * e,
+ struct ldap_state * pvt,
+ void *vresultp, char *buffer, size_t buflen)
+{
+ int attr;
+ int nvals;
+ int valcount = 0;
+ char **vals;
+ char **valiter;
+ struct __netgrent *result = vresultp;
+ enum nss_status stat = NSS_STATUS_SUCCESS;
+
+ for (attr = 0; attr < 2; attr++)
+ {
+ switch (attr)
+ {
+ case 1:
+ vals = _nss_ldap_get_values (e, AT (nisNetgroupTriple));
+ break;
+ default:
+ vals = _nss_ldap_get_values (e, AT (memberNisNetgroup));
+ break;
+ }
+
+ nvals = ldap_count_values (vals);
+
+ if (vals == NULL)
+ continue;
+
+ if (nvals == 0)
+ {
+ ldap_value_free (vals);
+ continue;
+ }
+
+ if (result->data_size > 0
+ && result->cursor - result->data + 1 > result->data_size)
+ EXPAND (1);
+
+ if (result->data_size > 0)
+ *result->cursor++ = ' ';
+
+ valcount += nvals;
+ valiter = vals;
+
+ while (*valiter != NULL)
+ {
+ int curlen = strlen (*valiter);
+ if (result->cursor - result->data + curlen + 1 > result->data_size)
+ EXPAND (curlen + 1);
+ memcpy (result->cursor, *valiter, curlen + 1);
+ result->cursor += curlen;
+ valiter++;
+ if (*valiter != NULL)
+ *result->cursor++ = ' ';
+ }
+ ldap_value_free (vals);
+ }
+
+ result->first = 1;
+ result->cursor = result->data;
+
+out:
+
+ return stat;
+}
+
+int nslcd_netgroup_byname(FILE *fp)
+{
+
+ int32_t tmpint32;
+ static struct ent_context *netgroup_context=NULL;
+ char *name;
+ /* these are here for now until we rewrite the LDAP code */
+ struct __netgrent result;
+ char buffer[1024];
+ int errnop;
+ struct ldap_args a;
+ enum nss_status stat=NSS_STATUS_SUCCESS;
+ /* read request parameters */
+ READ_STRING_ALLOC(fp,name);
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_netgroup_byname(%s)",name);
+ /* write the response header */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_NETGROUP_BYNAME);
+ /* initialize structure */
+ result.data=result.cursor=NULL;
+ result.data_size = 0;
+ /* do initial ldap request */
+ LA_INIT(a);
+ LA_STRING(a)=name;
+ LA_TYPE(a)=LA_TYPE_STRING;
+ stat=_nss_ldap_getbyname(&a,&result,buffer,1024,&errnop,_nss_ldap_filt_getnetgrent,LM_NETGROUP,_nss_ldap_load_netgr);
+ if (_nss_ldap_ent_context_init(&netgroup_context)==NULL)
+ return -1;
+ /* loop over all results */
+ while ((stat=_nss_ldap_parse_netgr(&result,buffer,1024))==NSS_STATUS_SUCCESS)
+ {
+ if (result.type==triple_val)
+ {
+ WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
+ WRITE_INT32(fp,NETGROUP_TYPE_TRIPLE);
+ if (result.val.triple.host==NULL)
+ { WRITE_STRING(fp,""); }
+ else
+ { WRITE_STRING(fp,result.val.triple.host); }
+ if (result.val.triple.user==NULL)
+ { WRITE_STRING(fp,""); }
+ else
+ { WRITE_STRING(fp,result.val.triple.user); }
+ if (result.val.triple.domain==NULL)
+ { WRITE_STRING(fp,""); }
+ else
+ { WRITE_STRING(fp,result.val.triple.domain); }
+ }
+ else if (result.type==group_val)
+ {
+ WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
+ WRITE_INT32(fp,NETGROUP_TYPE_NETGROUP);
+ WRITE_STRING(fp,result.val.group);
+ }
+ }
+ /* free data */
+ if (result.data!=NULL)
+ free(result.data);
+ /* we're done */
+ _nss_ldap_enter();
+ _nss_ldap_ent_context_release(netgroup_context);
+ _nss_ldap_leave();
+ return 0;
+}
+