diff options
Diffstat (limited to 'libc-top-half/musl/src/passwd/nscd_query.c')
-rw-r--r-- | libc-top-half/musl/src/passwd/nscd_query.c | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/libc-top-half/musl/src/passwd/nscd_query.c b/libc-top-half/musl/src/passwd/nscd_query.c new file mode 100644 index 0000000..dc3406b --- /dev/null +++ b/libc-top-half/musl/src/passwd/nscd_query.c @@ -0,0 +1,115 @@ +#include <sys/socket.h> +#include <byteswap.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <limits.h> +#include "nscd.h" + +static const struct { + short sun_family; + char sun_path[21]; +} addr = { + AF_UNIX, + "/var/run/nscd/socket" +}; + +FILE *__nscd_query(int32_t req, const char *key, int32_t *buf, size_t len, int *swap) +{ + size_t i; + int fd; + FILE *f = 0; + int32_t req_buf[REQ_LEN] = { + NSCDVERSION, + req, + strnlen(key,LOGIN_NAME_MAX)+1 + }; + struct msghdr msg = { + .msg_iov = (struct iovec[]){ + {&req_buf, sizeof(req_buf)}, + {(char*)key, strlen(key)+1} + }, + .msg_iovlen = 2 + }; + int errno_save = errno; + + *swap = 0; +retry: + memset(buf, 0, len); + buf[0] = NSCDVERSION; + + fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (fd < 0) { + if (errno == EAFNOSUPPORT) { + f = fopen("/dev/null", "re"); + if (f) + errno = errno_save; + return f; + } + return 0; + } + + if(!(f = fdopen(fd, "r"))) { + close(fd); + return 0; + } + + if (req_buf[2] > LOGIN_NAME_MAX) + return f; + + if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + /* If there isn't a running nscd we simulate a "not found" + * result and the caller is responsible for calling + * fclose on the (unconnected) socket. The value of + * errno must be left unchanged in this case. */ + if (errno == EACCES || errno == ECONNREFUSED || errno == ENOENT) { + errno = errno_save; + return f; + } + goto error; + } + + if (sendmsg(fd, &msg, MSG_NOSIGNAL) < 0) + goto error; + + if (!fread(buf, len, 1, f)) { + /* If the VERSION entry mismatches nscd will disconnect. The + * most likely cause is that the endianness mismatched. So, we + * byteswap and try once more. (if we already swapped, just + * fail out) + */ + if (ferror(f)) goto error; + if (!*swap) { + fclose(f); + for (i = 0; i < sizeof(req_buf)/sizeof(req_buf[0]); i++) { + req_buf[i] = bswap_32(req_buf[i]); + } + *swap = 1; + goto retry; + } else { + errno = EIO; + goto error; + } + } + + if (*swap) { + for (i = 0; i < len/sizeof(buf[0]); i++) { + buf[i] = bswap_32(buf[i]); + } + } + + /* The first entry in every nscd response is the version number. This + * really shouldn't happen, and is evidence of some form of malformed + * response. + */ + if(buf[0] != NSCDVERSION) { + errno = EIO; + goto error; + } + + return f; +error: + fclose(f); + return 0; +} |