summaryrefslogtreecommitdiffstats
path: root/src/sss_client
diff options
context:
space:
mode:
authorStephen Gallagher <sgallagh@redhat.com>2010-08-23 16:05:47 -0400
committerStephen Gallagher <sgallagh@redhat.com>2010-10-13 09:49:37 -0400
commitf128b7b865062da662127712935dcc58bd022384 (patch)
treebef6687ca4bebddf3d57c49f77a65697eecba44b /src/sss_client
parentf1ac7d7859b26f0f36f5e8ffacda609f8ece80e5 (diff)
downloadsssd-f128b7b865062da662127712935dcc58bd022384.tar.gz
sssd-f128b7b865062da662127712935dcc58bd022384.tar.xz
sssd-f128b7b865062da662127712935dcc58bd022384.zip
Add support for netgroups to NSS sss_client
Diffstat (limited to 'src/sss_client')
-rw-r--r--src/sss_client/nss_compat.h67
-rw-r--r--src/sss_client/nss_netgroup.c292
-rw-r--r--src/sss_client/sss_cli.h4
-rw-r--r--src/sss_client/sss_nss.exports6
4 files changed, 364 insertions, 5 deletions
diff --git a/src/sss_client/nss_compat.h b/src/sss_client/nss_compat.h
new file mode 100644
index 000000000..37871c230
--- /dev/null
+++ b/src/sss_client/nss_compat.h
@@ -0,0 +1,67 @@
+/*
+ SSSD
+
+ nss_compat.h
+
+ Authors:
+ Stephen Gallagher <sgallagh@redhat.com>
+
+ Copyright (C) 2010 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ Portions of this source file were copied from nss-pam-ldapd version
+ 0.7.8, licensed under LGPLv2.1+
+*/
+
+#ifndef NSS_COMPAT_H_
+#define NSS_COMPAT_H_
+
+/* We also define struct __netgrent because it's definition is
+ not publically available. This is taken from inet/netgroup.h
+ of the glibc (2.3.6) source tarball.
+ The first part of the struct is the only part that is modified
+ by our getnetgrent() function, all the other fields are not
+ touched at all. */
+struct __netgrent
+{
+ enum { triple_val, group_val } type;
+ union
+ {
+ struct
+ {
+ const char *host;
+ const char *user;
+ const char *domain;
+ } triple;
+ const char *group;
+ } val;
+ /* the following stuff is used by some NSS services
+ but not by ours (it's not completely clear how these
+ are shared between different services) or is used
+ by our caller */
+ char *data;
+ size_t data_size;
+ union
+ {
+ char *cursor;
+ unsigned long int position;
+ } insertedname; /* added name to union to avoid warning */
+ int first;
+ struct name_list *known_groups;
+ struct name_list *needed_groups;
+ void *nip; /* changed from `service_user *nip' */
+};
+
+#endif /* NSS_COMPAT_H_ */
diff --git a/src/sss_client/nss_netgroup.c b/src/sss_client/nss_netgroup.c
new file mode 100644
index 000000000..f70283fa2
--- /dev/null
+++ b/src/sss_client/nss_netgroup.c
@@ -0,0 +1,292 @@
+/*
+ SSSD
+
+ nss_netgroup.c
+
+ Authors:
+ Stephen Gallagher <sgallagh@redhat.com>
+
+ Copyright (C) 2010 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <nss.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include "sss_cli.h"
+#include "nss_compat.h"
+
+#define MAX_NETGR_NAME_LENGTH 2048
+
+static struct sss_nss_getnetgrent_data {
+ char *name;
+ size_t len;
+ size_t ptr;
+ uint8_t *data;
+} sss_nss_getnetgrent_data;
+
+/*
+ * Replies:
+ *
+ * 0-3: 32bit unsigned number of results
+ * 4-7: 32bit unsigned (reserved/padding)
+ * For each result:
+ * 8-X: sequence of \0 terminated strings representing tuple
+ * (host, user, domain)
+ */
+#define NETGR_METADATA_COUNT 2 * sizeof(uint32_t)
+struct sss_nss_netgr_rep {
+ struct __netgrent *result;
+ char *buffer;
+ size_t buflen;
+};
+
+static void sss_nss_getnetgrent_data_clean(void) {
+ if (sss_nss_getnetgrent_data.name != NULL) {
+ free(sss_nss_getnetgrent_data.name);
+ sss_nss_getnetgrent_data.name = NULL;
+ }
+ if (sss_nss_getnetgrent_data.data != NULL) {
+ free(sss_nss_getnetgrent_data.data);
+ sss_nss_getnetgrent_data.data = NULL;
+ }
+ sss_nss_getnetgrent_data.len = 0;
+ sss_nss_getnetgrent_data.ptr = 0;
+}
+
+static int sss_nss_getnetgr_readrep(struct sss_nss_netgr_rep *pr,
+ uint8_t *buf, size_t *len)
+{
+ char *sbuf;
+ size_t i, slen;
+ ssize_t dlen;
+
+ if (*len < 3) {
+ /* Not enough space for data, bad packet */
+ return EBADMSG;
+ }
+
+ sbuf = (char *)&buf[0];
+ slen = *len;
+ dlen = pr->buflen;
+
+ /* Host value */
+ i = 0;
+ pr->result->val.triple.host = &(pr->buffer[i]);
+ while (slen > i && dlen > 0) {
+ pr->buffer[i] = sbuf[i];
+ if (pr->buffer[i] == '\0') break;
+ i++;
+ dlen--;
+ }
+ if (slen <= i) { /* premature end of buf */
+ return EBADMSG;
+ }
+ if (dlen <= 0) { /* not enough memory */
+ return ERANGE; /* not ENOMEM, ERANGE is what glibc looks for */
+ }
+ i++;
+ dlen--;
+
+ /* libc expects NULL instead of empty string */
+ if (strlen(pr->result->val.triple.host) == 0) {
+ pr->result->val.triple.host = NULL;
+ }
+
+ /* User value */
+ pr->result->val.triple.user = &(pr->buffer[i]);
+ while (slen > i && dlen > 0) {
+ pr->buffer[i] = sbuf[i];
+ if (pr->buffer[i] == '\0') break;
+ i++;
+ dlen--;
+ }
+ if (slen <= i) { /* premature end of buf */
+ return EBADMSG;
+ }
+ if (dlen <= 0) { /* not enough memory */
+ return ERANGE; /* not ENOMEM, ERANGE is what glibc looks for */
+ }
+ i++;
+ dlen--;
+
+ /* libc expects NULL instead of empty string */
+ if (strlen(pr->result->val.triple.user) == 0) {
+ pr->result->val.triple.user = NULL;
+ }
+
+ /* Domain value */
+ pr->result->val.triple.domain = &(pr->buffer[i]);
+ while (slen > i && dlen > 0) {
+ pr->buffer[i] = sbuf[i];
+ if (pr->buffer[i] == '\0') break;
+ i++;
+ dlen--;
+ }
+ if (slen <= i) { /* premature end of buf */
+ return EBADMSG;
+ }
+ if (dlen <= 0) { /* not enough memory */
+ return ERANGE; /* not ENOMEM, ERANGE is what glibc looks for */
+ }
+ i++;
+ dlen--;
+
+ /* libc expects NULL instead of empty string */
+ if (strlen(pr->result->val.triple.domain) == 0) {
+ pr->result->val.triple.domain = NULL;
+ }
+
+ *len = slen -i;
+
+ return 0;
+}
+
+enum nss_status _nss_sss_setnetgrent(const char *netgroup,
+ struct __netgrent *result)
+{
+ uint8_t *repbuf = NULL;
+ size_t replen;
+ enum nss_status nret;
+ struct sss_cli_req_data rd;
+ int errnop;
+ size_t name_len;
+ errno_t ret;
+
+ if (!netgroup) return NSS_STATUS_NOTFOUND;
+
+ /* make sure we do not have leftovers, and release memory */
+ sss_nss_getnetgrent_data_clean();
+
+ ret = sss_strnlen(netgroup, MAX_NETGR_NAME_LENGTH, &name_len);
+ if (ret != 0) return NSS_STATUS_NOTFOUND;
+
+ sss_nss_getnetgrent_data.name = malloc(sizeof(char)*name_len + 1);
+ if (sss_nss_getnetgrent_data.name == NULL) {
+ return NSS_STATUS_TRYAGAIN;
+ }
+ strncpy(sss_nss_getnetgrent_data.name, netgroup, name_len + 1);
+
+ rd.data = sss_nss_getnetgrent_data.name;
+ rd.len = name_len + 1;
+
+ nret = sss_nss_make_request(SSS_NSS_SETNETGRENT, &rd,
+ &repbuf, &replen, &errnop);
+ if (nret != NSS_STATUS_SUCCESS) {
+ errno = errnop;
+ return nret;
+ }
+
+ /* no results if not found */
+ if ((((uint32_t *)repbuf)[0] == 0) || (replen < NETGR_METADATA_COUNT)) {
+ free(repbuf);
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status _nss_sss_getnetgrent_r(struct __netgrent *result,
+ char *buffer, size_t buflen,
+ int *errnop)
+{
+ struct sss_cli_req_data rd;
+ struct sss_nss_netgr_rep netgrrep;
+ uint8_t *repbuf;
+ size_t replen;
+ enum nss_status nret;
+ uint32_t num_entries;
+ int ret;
+
+ /* Caught once glibc passing in buffer == 0x0 */
+ if (!buffer || !buflen) return ERANGE;
+
+ /* If we're already processing result data, continue to
+ * return it.
+ */
+ if (sss_nss_getnetgrent_data.data != NULL &&
+ sss_nss_getnetgrent_data.ptr < sss_nss_getnetgrent_data.len) {
+
+ repbuf = (uint8_t *)sss_nss_getnetgrent_data.data +
+ sss_nss_getnetgrent_data.ptr;
+ replen = sss_nss_getnetgrent_data.len -
+ sss_nss_getnetgrent_data.ptr;
+
+ netgrrep.result = result;
+ netgrrep.buffer = buffer;
+ netgrrep.buflen = buflen;
+
+ ret = sss_nss_getnetgr_readrep(&netgrrep, repbuf, &replen);
+ if (ret != 0) {
+ *errnop = ret;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ sss_nss_getnetgrent_data.ptr = sss_nss_getnetgrent_data.len - replen;
+
+ return NSS_STATUS_SUCCESS;
+ }
+
+ /* Release memory, if any */
+ sss_nss_getnetgrent_data_clean();
+
+ /* retrieve no more than SSS_NSS_MAX_ENTRIES at a time */
+ num_entries = SSS_NSS_MAX_ENTRIES;
+ rd.len = sizeof(uint32_t);
+ rd.data = &num_entries;
+
+ nret = sss_nss_make_request(SSS_NSS_GETNETGRENT, &rd,
+ &repbuf, &replen, errnop);
+ if (nret != NSS_STATUS_SUCCESS) {
+ return nret;
+ }
+
+ /* no results if not found */
+ if ((((uint32_t *)repbuf)[0] == 0) || (replen <= NETGR_METADATA_COUNT)) {
+ free(repbuf);
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ sss_nss_getnetgrent_data.data = repbuf;
+ sss_nss_getnetgrent_data.len = replen;
+ /* skip metadata fields */
+ sss_nss_getnetgrent_data.ptr = NETGR_METADATA_COUNT;
+
+ /* call again ourselves, this will return the first result */
+ return _nss_sss_getnetgrent_r(result, buffer, buflen, errnop);
+}
+
+enum nss_status _nss_sss_endnetgrent(void)
+{
+ enum nss_status nret;
+ int errnop;
+
+ /* make sure we do not have leftovers, and release memory */
+ sss_nss_getnetgrent_data_clean();
+
+ nret = sss_nss_make_request(SSS_NSS_ENDNETGRENT,
+ NULL, NULL, NULL, &errnop);
+ if (nret != NSS_STATUS_SUCCESS) {
+ errno = errnop;
+ return nret;
+ }
+
+ return NSS_STATUS_SUCCESS;
+}
diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
index e0a33df46..1a068d5f3 100644
--- a/src/sss_client/sss_cli.h
+++ b/src/sss_client/sss_cli.h
@@ -93,14 +93,14 @@ enum sss_cli_command {
SSS_NSS_SETHOSTENT = 0x0054,
SSS_NSS_GETHOSTENT = 0x0055,
SSS_NSS_ENDHOSTENT = 0x0056,
-
+#endif
/* netgroup */
SSS_NSS_SETNETGRENT = 0x0061,
SSS_NSS_GETNETGRENT = 0x0062,
SSS_NSS_ENDNETGRENT = 0x0063,
/* SSS_NSS_INNETGR = 0x0064, */
-
+#if 0
/* networks */
SSS_NSS_GETNETBYNAME = 0x0071,
diff --git a/src/sss_client/sss_nss.exports b/src/sss_client/sss_nss.exports
index bcc6b10e1..2fa4e5f2f 100644
--- a/src/sss_client/sss_nss.exports
+++ b/src/sss_client/sss_nss.exports
@@ -34,9 +34,9 @@ EXPORTED {
#_nss_sss_gethostent_r;
#_nss_sss_endhostent;
- #_nss_sss_setnetgrent;
- #_nss_sss_getnetgrent_r;
- #_nss_sss_endnetgrent;
+ _nss_sss_setnetgrent;
+ _nss_sss_getnetgrent_r;
+ _nss_sss_endnetgrent;
#_nss_sss_getnetbyname_r;
#_nss_sss_getnetbyaddr_r;