diff options
Diffstat (limited to 'src/sss_client/nss_services.c')
-rw-r--r-- | src/sss_client/nss_services.c | 129 |
1 files changed, 125 insertions, 4 deletions
diff --git a/src/sss_client/nss_services.c b/src/sss_client/nss_services.c index e6aea58b..3f042b4a 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 * @@ -340,22 +355,128 @@ 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 - SVC_METADATA_COUNT == 0)) { + free(repbuf); + return NSS_STATUS_NOTFOUND; + } + + sss_nss_getservent_data.data = repbuf; + sss_nss_getservent_data.len = replen; + + /* skip metadata fields */ + sss_nss_getservent_data.ptr = SVC_METADATA_COUNT; + + /* 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; } |