Index: fusl/src/passwd/nscd_query.c |
diff --git a/fusl/src/passwd/nscd_query.c b/fusl/src/passwd/nscd_query.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d38e371bcda395855a4e9a125d4a75a115c76416 |
--- /dev/null |
+++ b/fusl/src/passwd/nscd_query.c |
@@ -0,0 +1,107 @@ |
+#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) return NULL; |
+ |
+ 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; |
+} |