From 0e3a97da6d7724349252f9bf82a637bff82644e4 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Mon, 23 Jan 2012 09:01:25 -0500
Subject: [PATCH 09/12] NSS: Add client support for [set|get|end]servent()

---
 src/sss_client/nss_services.c |  126 +++++++++++++++++++++++++++++++++++++++-
 1 files changed, 122 insertions(+), 4 deletions(-)

diff --git a/src/sss_client/nss_services.c b/src/sss_client/nss_services.c
index 1db9b76c3c033ce67431dc1dc3377e47b40d5c10..f486482f4ce4f2d8699b238c87724f848c4387e3 100644
--- a/src/sss_client/nss_services.c
+++ b/src/sss_client/nss_services.c
@@ -31,6 +31,21 @@
 #include <string.h>
 #include "sss_cli.h"
 
+static struct sss_nss_getservent_data {
+    size_t len;
+    size_t ptr;
+    uint8_t *data;
+} sss_nss_getservent_data;
+
+static void sss_nss_getservent_data_clean(void) {
+
+    if (sss_nss_getservent_data.data != NULL) {
+        free(sss_nss_getservent_data.data);
+        sss_nss_getservent_data.data = NULL;
+    }
+    sss_nss_getservent_data.len = 0;
+    sss_nss_getservent_data.ptr = 0;
+}
 
 /* GETSERVBYNAME Request
  *
@@ -336,22 +351,125 @@ out:
 enum nss_status
 _nss_sss_setservent(void)
 {
-    return NSS_STATUS_UNAVAIL;
+    enum nss_status nret;
+    int errnop;
+    sss_nss_lock();
+
+    /* make sure we do not have leftovers, and release memory */
+    sss_nss_getservent_data_clean();
+
+    nret = sss_nss_make_request(SSS_NSS_SETSERVENT,
+                                NULL, NULL, NULL, &errnop);
+    if (nret != NSS_STATUS_SUCCESS) {
+        errno = errnop;
+    }
+
+    sss_nss_unlock();
+    return nret;
 }
 
+static enum nss_status internal_getservent_r(struct servent *result,
+                                             char *buffer, size_t buflen,
+                                             int *errnop);
 
 enum nss_status
 _nss_sss_getservent_r(struct servent *result,
                       char *buffer, size_t buflen,
                       int *errnop)
 {
-    fprintf(stderr, "getservent [%s]\n", buffer);
-    return NSS_STATUS_UNAVAIL;
+    enum nss_status nret;
+
+    sss_nss_lock();
+    nret = internal_getservent_r(result, buffer, buflen, errnop);
+    sss_nss_unlock();
+
+    return nret;
+}
+
+static enum nss_status internal_getservent_r(struct servent *result,
+                                             char *buffer, size_t buflen,
+                                             int *errnop)
+{
+    struct sss_cli_req_data rd;
+    struct sss_nss_svc_rep pwrep;
+    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 there are leftovers return the next one */
+    if (sss_nss_getservent_data.data != NULL &&
+        sss_nss_getservent_data.ptr < sss_nss_getservent_data.len) {
+
+        repbuf = sss_nss_getservent_data.data + sss_nss_getservent_data.ptr;
+        replen = sss_nss_getservent_data.len - sss_nss_getservent_data.ptr;
+
+        pwrep.result = result;
+        pwrep.buffer = buffer;
+        pwrep.buflen = buflen;
+
+        ret = sss_nss_getsvc_readrep(&pwrep, repbuf, &replen);
+        if (ret) {
+            *errnop = ret;
+            return NSS_STATUS_TRYAGAIN;
+        }
+
+        /* advance buffer pointer */
+        sss_nss_getservent_data.ptr = sss_nss_getservent_data.len - replen;
+
+        return NSS_STATUS_SUCCESS;
+    }
+
+    /* release memory if any */
+    sss_nss_getservent_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_GETSERVENT, &rd,
+                                &repbuf, &replen, errnop);
+    if (nret != NSS_STATUS_SUCCESS) {
+        return nret;
+    }
+
+    /* no results if not found */
+    if ((((uint32_t *)repbuf)[0] == 0) || (replen - 8 == 0)) {
+        free(repbuf);
+        return NSS_STATUS_NOTFOUND;
+    }
+
+    sss_nss_getservent_data.data = repbuf;
+    sss_nss_getservent_data.len = replen;
+    sss_nss_getservent_data.ptr = 8; /* skip metadata fields */
+
+    /* call again ourselves, this will return the first result */
+    return internal_getservent_r(result, buffer, buflen, errnop);
 }
 
 
 enum nss_status
 _nss_sss_endservent(void)
 {
-    return NSS_STATUS_UNAVAIL;
+    enum nss_status nret;
+    int errnop;
+
+    sss_nss_lock();
+
+    /* make sure we do not have leftovers, and release memory */
+    sss_nss_getservent_data_clean();
+
+    nret = sss_nss_make_request(SSS_NSS_ENDSERVENT,
+                                NULL, NULL, NULL, &errnop);
+    if (nret != NSS_STATUS_SUCCESS) {
+        errno = errnop;
+    }
+
+    sss_nss_unlock();
+    return nret;
 }
-- 
1.7.7.5

