diff options
author | Stephen Gallagher <sgallagh@redhat.com> | 2012-01-06 13:57:30 -0500 |
---|---|---|
committer | Stephen Gallagher <sgallagh@redhat.com> | 2012-01-27 09:02:01 -0500 |
commit | cc7ee57f3adada83ac657e69636ca995d5b6948e (patch) | |
tree | 6d030166c6251e1813900ccd762b26eec1771f83 | |
parent | ff907ba7a9b5e429de086515642f97a0447e546a (diff) | |
download | sssd-cc7ee57f3adada83ac657e69636ca995d5b6948e.tar.gz sssd-cc7ee57f3adada83ac657e69636ca995d5b6948e.tar.bz2 sssd-cc7ee57f3adada83ac657e69636ca995d5b6948e.zip |
NSS: Add client support for services (non-enumeration)
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | src/sss_client/nss_services.c | 361 | ||||
-rw-r--r-- | src/sss_client/sss_cli.h | 22 | ||||
-rw-r--r-- | src/sss_client/sss_nss.exports | 10 |
4 files changed, 389 insertions, 5 deletions
diff --git a/Makefile.am b/Makefile.am index 93c5ff56..76aa91c2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -849,6 +849,7 @@ libnss_sss_la_SOURCES = \ src/sss_client/nss_passwd.c \ src/sss_client/nss_group.c \ src/sss_client/nss_netgroup.c \ + src/sss_client/nss_services.c \ src/sss_client/sss_cli.h \ src/sss_client/nss_compat.h libnss_sss_la_LDFLAGS = \ diff --git a/src/sss_client/nss_services.c b/src/sss_client/nss_services.c new file mode 100644 index 00000000..e6aea58b --- /dev/null +++ b/src/sss_client/nss_services.c @@ -0,0 +1,361 @@ +/* + SSSD + + Authors: + Stephen Gallagher <sgallagh@redhat.com> + + Copyright (C) 2012 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 <netdb.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" + + +/* GETSERVBYNAME Request + * + * 0-X: Sequence of two, zero-terminated strings (name, protocol). + * Protocol may be zero-length to imply "any" + * + * GETSERVBYPORT Request: + * 0-3: 16-bit port number in network byte order + * 4-7: Reserved/padding + * 8-X: Zero-terminated string (protocol) + * Protocol may be zero-length to imply "any" + * + * Replies: + * 0-3: 32-bit unsigned number of results + * 4-7: 32-bit unsigned (reserved/padding) + * 7-X: Result data (blocks equal to number of results) + * + * Result data: + * 0-3: 32-bit unsigned port number in network byte order + * 4-7: 32-bit unsigned number of aliases + * 8-X: sequence of zero-terminated strings + * (name, protocol, zero or more aliases) + */ +struct sss_nss_svc_rep { + struct servent *result; + char *buffer; + size_t buflen; +}; + +#define SVC_METADATA_COUNT 8 + +static errno_t +sss_nss_getsvc_readrep(struct sss_nss_svc_rep *sr, + uint8_t *buf, size_t *len) +{ + errno_t ret; + uint32_t c; + uint32_t num_aliases; + size_t i, l, slen, dlen, pad, ptaliases, alen; + char *sbuf; + + /* Buffer must contain two 32-bit integers, + * at least one character and null-terminator + * for the name, and at least a null- + * terminator for the protocol. + */ + if (*len < 11) { + /* not enough space for data, bad packet */ + return EBADMSG; + } + + /* Get the port */ + SAFEALIGN_COPY_UINT32(&c, buf, NULL); + sr->result->s_port = (uint16_t)c; + + /* Get the number of aliases */ + SAFEALIGN_COPY_UINT32(&num_aliases, buf + sizeof(uint32_t), NULL); + + sbuf = (char *)&buf[2 * sizeof(uint32_t)]; + slen = *len - (2 * sizeof(uint32_t)); + dlen = sr->buflen; + + /* Copy in the name */ + i = 0; + sr->result->s_name = &(sr->buffer[i]); + + ret = sss_readrep_copy_string(sbuf, &i, + &slen, &dlen, + &sr->result->s_name, + NULL); + if (ret != EOK) return ret; + + /* Copy in the protocol */ + sr->result->s_proto = &(sr->buffer[i]); + + ret = sss_readrep_copy_string(sbuf, &i, + &slen, &dlen, + &sr->result->s_proto, + NULL); + if (ret != EOK) return ret; + + /* Make sure sr->buffer[i+pad] is 32-bit aligned */ + pad = 0; + while((i + pad) % 4) { + pad++; + } + + /* Copy in the aliases */ + sr->result->s_aliases = (char **) &(sr->buffer[i+pad]); + + ptaliases = (sizeof(char *) * (num_aliases + 1)) + pad; + if (ptaliases > dlen) { + return ERANGE; /* not ENOMEM, ERANGE is what glibc looks for */ + } + + dlen -= ptaliases; + ptaliases += i; + sr->result->s_aliases[num_aliases] = NULL; /* terminate array */ + + for (l = 0; l < num_aliases; l++) { + sr->result->s_aliases[l] = &(sr->buffer[ptaliases]); + ret = sss_readrep_copy_string(sbuf, &i, + &slen, &dlen, + &sr->result->s_aliases[l], + &alen); + if (ret != EOK) return ret; + + ptaliases += alen + 1; + } + + *len = slen - i; + + return EOK; +} + +enum nss_status +_nss_sss_getservbyname_r(const char *name, + const char *protocol, + struct servent *result, + char *buffer, size_t buflen, + int *errnop) +{ + struct sss_cli_req_data rd; + struct sss_nss_svc_rep svcrep; + size_t name_len; + size_t proto_len = 0; + uint8_t *repbuf; + uint8_t *data; + size_t replen, len; + enum nss_status nret; + int ret; + + /* Caught once glibc passing in buffer == 0x0 */ + if (!buffer || !buflen) return ERANGE; + + ret = sss_strnlen(name, SSS_NAME_MAX, &name_len); + if (ret != 0) { + *errnop = EINVAL; + return NSS_STATUS_NOTFOUND; + } + + if (protocol) { + ret = sss_strnlen(protocol, SSS_NAME_MAX, &proto_len); + if (ret != 0) { + *errnop = EINVAL; + return NSS_STATUS_NOTFOUND; + } + } + + rd.len = name_len + proto_len + 2; + data = malloc(sizeof(uint8_t)*rd.len); + if (data == NULL) { + nret = NSS_STATUS_TRYAGAIN; + goto out; + } + + memcpy(data, name, name_len + 1); + + if (protocol) { + memcpy(data + name_len + 1, protocol, proto_len + 1); + } else { + /* No protocol specified, pass empty string */ + data[name_len + 1] = '\0'; + } + rd.data = data; + + sss_nss_lock(); + + nret = sss_nss_make_request(SSS_NSS_GETSERVBYNAME, &rd, + &repbuf, &replen, errnop); + free(data); + if (nret != NSS_STATUS_SUCCESS) { + goto out; + } + + svcrep.result = result; + svcrep.buffer = buffer; + svcrep.buflen = buflen; + + /* no results if not found */ + if (((uint32_t *)repbuf)[0] == 0) { + free(repbuf); + nret = NSS_STATUS_NOTFOUND; + goto out; + } + + /* only 1 result is accepted for this function */ + if (((uint32_t *)repbuf)[0] != 1) { + *errnop = EBADMSG; + free(repbuf); + nret = NSS_STATUS_TRYAGAIN; + goto out; + } + + len = replen - SVC_METADATA_COUNT; + ret = sss_nss_getsvc_readrep(&svcrep, + repbuf + SVC_METADATA_COUNT, + &len); + free(repbuf); + if (ret) { + *errnop = ret; + nret = NSS_STATUS_TRYAGAIN; + goto out; + } + + nret = NSS_STATUS_SUCCESS; + +out: + sss_nss_unlock(); + return nret; +} + + +enum nss_status +_nss_sss_getservbyport_r(int port, const char *protocol, + struct servent *result, + char *buffer, size_t buflen, + int *errnop) +{ + struct sss_cli_req_data rd; + struct sss_nss_svc_rep svcrep; + size_t proto_len = 0; + uint8_t *repbuf; + uint8_t *data; + size_t replen, len; + enum nss_status nret; + int ret; + + /* Caught once glibc passing in buffer == 0x0 */ + if (!buffer || !buflen) return ERANGE; + + if (protocol) { + ret = sss_strnlen(protocol, SSS_NAME_MAX, &proto_len); + if (ret != 0) { + *errnop = EINVAL; + return NSS_STATUS_NOTFOUND; + } + } + + rd.len = sizeof(uint32_t)*2 + proto_len + 1; + data = malloc(sizeof(char)*rd.len); + if (data == NULL) { + nret = NSS_STATUS_TRYAGAIN; + goto out; + } + + SAFEALIGN_SET_UINT32(data, port, NULL); + + /* Padding */ + memset(data + sizeof(uint32_t), 0, 4); + + if (protocol) { + memcpy(data + sizeof(uint32_t)*2, protocol, proto_len + 1); + } else { + /* No protocol specified, pass empty string */ + data[sizeof(uint32_t)*2] = '\0'; + } + rd.data = data; + + sss_nss_lock(); + + nret = sss_nss_make_request(SSS_NSS_GETSERVBYPORT, &rd, + &repbuf, &replen, errnop); + free(data); + if (nret != NSS_STATUS_SUCCESS) { + goto out; + } + + svcrep.result = result; + svcrep.buffer = buffer; + svcrep.buflen = buflen; + + /* no results if not found */ + if (((uint32_t *)repbuf)[0] == 0) { + free(repbuf); + nret = NSS_STATUS_NOTFOUND; + goto out; + } + + /* only 1 result is accepted for this function */ + if (((uint32_t *)repbuf)[0] != 1) { + *errnop = EBADMSG; + free(repbuf); + nret = NSS_STATUS_TRYAGAIN; + goto out; + } + + len = replen - SVC_METADATA_COUNT; + ret = sss_nss_getsvc_readrep(&svcrep, + repbuf + SVC_METADATA_COUNT, + &len); + free(repbuf); + if (ret) { + *errnop = ret; + nret = NSS_STATUS_TRYAGAIN; + goto out; + } + + nret = NSS_STATUS_SUCCESS; + +out: + sss_nss_unlock(); + return nret; +} + + +enum nss_status +_nss_sss_setservent(void) +{ + return NSS_STATUS_UNAVAIL; +} + + +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 +_nss_sss_endservent(void) +{ + return NSS_STATUS_UNAVAIL; +} diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h index c6e53e60..7dc60d40 100644 --- a/src/sss_client/sss_cli.h +++ b/src/sss_client/sss_cli.h @@ -138,6 +138,7 @@ enum sss_cli_command { SSS_NSS_SETRPCENT = 0x0093, SSS_NSS_GETRPCENT = 0x0094, SSS_NSS_ENDRPCENT = 0x0095, +#endif /* services */ @@ -147,6 +148,7 @@ enum sss_cli_command { SSS_NSS_GETSERVENT = 0x00A4, SSS_NSS_ENDSERVENT = 0x00A5, +#if 0 /* shadow */ SSS_NSS_GETSPNAM = 0x00B1, @@ -476,10 +478,30 @@ safealign_memcpy(void *dest, const void *src, size_t n, size_t *counter) } } +#define SAFEALIGN_SET_VALUE(dest, value, type, pctr) do { \ + type CV_MACRO_val = (type)(value); \ + safealign_memcpy(dest, &CV_MACRO_val, sizeof(type), pctr); \ +} while(0) + +#ifndef SAFEALIGN_SET_UINT32 +#define SAFEALIGN_SET_UINT32(dest, value, pctr) \ + SAFEALIGN_SET_VALUE(dest, value, uint32_t, pctr) +#endif + #define SAFEALIGN_COPY_UINT32(dest, src, pctr) \ safealign_memcpy(dest, src, sizeof(uint32_t), pctr) #endif +#ifndef SAFEALIGN_SET_UINT16 +#define SAFEALIGN_SET_UINT16(dest, value, pctr) \ + SAFEALIGN_SET_VALUE(dest, value, uint16_t, pctr) +#endif + +#ifndef SAFEALIGN_COPY_UINT16 +#define SAFEALIGN_COPY_UINT16(dest, src, pctr) \ + safealign_memcpy(dest, src, sizeof(uint16_t), pctr) +#endif + #if 0 /* GETSPNAM Request: diff --git a/src/sss_client/sss_nss.exports b/src/sss_client/sss_nss.exports index 2fa4e5f2..1eefea8d 100644 --- a/src/sss_client/sss_nss.exports +++ b/src/sss_client/sss_nss.exports @@ -56,11 +56,11 @@ EXPORTED { #_nss_sss_getrpcent_r; #_nss_sss_endrpcent; - #_nss_sss_getservbyname_r; - #_nss_sss_getservbyport_r; - #_nss_sss_setservent; - #_nss_sss_getservent_r; - #_nss_sss_endservent; + _nss_sss_getservbyname_r; + _nss_sss_getservbyport_r; + _nss_sss_setservent; + _nss_sss_getservent_r; + _nss_sss_endservent; #_nss_sss_getspnam_r; #_nss_sss_setspent; |