1*c9945492SAndroid Build Coastguard Worker #include <sys/socket.h>
2*c9945492SAndroid Build Coastguard Worker #include <byteswap.h>
3*c9945492SAndroid Build Coastguard Worker #include <unistd.h>
4*c9945492SAndroid Build Coastguard Worker #include <stdio.h>
5*c9945492SAndroid Build Coastguard Worker #include <string.h>
6*c9945492SAndroid Build Coastguard Worker #include <errno.h>
7*c9945492SAndroid Build Coastguard Worker #include <limits.h>
8*c9945492SAndroid Build Coastguard Worker #include "nscd.h"
9*c9945492SAndroid Build Coastguard Worker
10*c9945492SAndroid Build Coastguard Worker static const struct {
11*c9945492SAndroid Build Coastguard Worker short sun_family;
12*c9945492SAndroid Build Coastguard Worker char sun_path[21];
13*c9945492SAndroid Build Coastguard Worker } addr = {
14*c9945492SAndroid Build Coastguard Worker AF_UNIX,
15*c9945492SAndroid Build Coastguard Worker "/var/run/nscd/socket"
16*c9945492SAndroid Build Coastguard Worker };
17*c9945492SAndroid Build Coastguard Worker
__nscd_query(int32_t req,const char * key,int32_t * buf,size_t len,int * swap)18*c9945492SAndroid Build Coastguard Worker FILE *__nscd_query(int32_t req, const char *key, int32_t *buf, size_t len, int *swap)
19*c9945492SAndroid Build Coastguard Worker {
20*c9945492SAndroid Build Coastguard Worker size_t i;
21*c9945492SAndroid Build Coastguard Worker int fd;
22*c9945492SAndroid Build Coastguard Worker FILE *f = 0;
23*c9945492SAndroid Build Coastguard Worker int32_t req_buf[REQ_LEN] = {
24*c9945492SAndroid Build Coastguard Worker NSCDVERSION,
25*c9945492SAndroid Build Coastguard Worker req,
26*c9945492SAndroid Build Coastguard Worker strnlen(key,LOGIN_NAME_MAX)+1
27*c9945492SAndroid Build Coastguard Worker };
28*c9945492SAndroid Build Coastguard Worker struct msghdr msg = {
29*c9945492SAndroid Build Coastguard Worker .msg_iov = (struct iovec[]){
30*c9945492SAndroid Build Coastguard Worker {&req_buf, sizeof(req_buf)},
31*c9945492SAndroid Build Coastguard Worker {(char*)key, strlen(key)+1}
32*c9945492SAndroid Build Coastguard Worker },
33*c9945492SAndroid Build Coastguard Worker .msg_iovlen = 2
34*c9945492SAndroid Build Coastguard Worker };
35*c9945492SAndroid Build Coastguard Worker int errno_save = errno;
36*c9945492SAndroid Build Coastguard Worker
37*c9945492SAndroid Build Coastguard Worker *swap = 0;
38*c9945492SAndroid Build Coastguard Worker retry:
39*c9945492SAndroid Build Coastguard Worker memset(buf, 0, len);
40*c9945492SAndroid Build Coastguard Worker buf[0] = NSCDVERSION;
41*c9945492SAndroid Build Coastguard Worker
42*c9945492SAndroid Build Coastguard Worker fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
43*c9945492SAndroid Build Coastguard Worker if (fd < 0) {
44*c9945492SAndroid Build Coastguard Worker if (errno == EAFNOSUPPORT) {
45*c9945492SAndroid Build Coastguard Worker f = fopen("/dev/null", "re");
46*c9945492SAndroid Build Coastguard Worker if (f)
47*c9945492SAndroid Build Coastguard Worker errno = errno_save;
48*c9945492SAndroid Build Coastguard Worker return f;
49*c9945492SAndroid Build Coastguard Worker }
50*c9945492SAndroid Build Coastguard Worker return 0;
51*c9945492SAndroid Build Coastguard Worker }
52*c9945492SAndroid Build Coastguard Worker
53*c9945492SAndroid Build Coastguard Worker if(!(f = fdopen(fd, "r"))) {
54*c9945492SAndroid Build Coastguard Worker close(fd);
55*c9945492SAndroid Build Coastguard Worker return 0;
56*c9945492SAndroid Build Coastguard Worker }
57*c9945492SAndroid Build Coastguard Worker
58*c9945492SAndroid Build Coastguard Worker if (req_buf[2] > LOGIN_NAME_MAX)
59*c9945492SAndroid Build Coastguard Worker return f;
60*c9945492SAndroid Build Coastguard Worker
61*c9945492SAndroid Build Coastguard Worker if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
62*c9945492SAndroid Build Coastguard Worker /* If there isn't a running nscd we simulate a "not found"
63*c9945492SAndroid Build Coastguard Worker * result and the caller is responsible for calling
64*c9945492SAndroid Build Coastguard Worker * fclose on the (unconnected) socket. The value of
65*c9945492SAndroid Build Coastguard Worker * errno must be left unchanged in this case. */
66*c9945492SAndroid Build Coastguard Worker if (errno == EACCES || errno == ECONNREFUSED || errno == ENOENT) {
67*c9945492SAndroid Build Coastguard Worker errno = errno_save;
68*c9945492SAndroid Build Coastguard Worker return f;
69*c9945492SAndroid Build Coastguard Worker }
70*c9945492SAndroid Build Coastguard Worker goto error;
71*c9945492SAndroid Build Coastguard Worker }
72*c9945492SAndroid Build Coastguard Worker
73*c9945492SAndroid Build Coastguard Worker if (sendmsg(fd, &msg, MSG_NOSIGNAL) < 0)
74*c9945492SAndroid Build Coastguard Worker goto error;
75*c9945492SAndroid Build Coastguard Worker
76*c9945492SAndroid Build Coastguard Worker if (!fread(buf, len, 1, f)) {
77*c9945492SAndroid Build Coastguard Worker /* If the VERSION entry mismatches nscd will disconnect. The
78*c9945492SAndroid Build Coastguard Worker * most likely cause is that the endianness mismatched. So, we
79*c9945492SAndroid Build Coastguard Worker * byteswap and try once more. (if we already swapped, just
80*c9945492SAndroid Build Coastguard Worker * fail out)
81*c9945492SAndroid Build Coastguard Worker */
82*c9945492SAndroid Build Coastguard Worker if (ferror(f)) goto error;
83*c9945492SAndroid Build Coastguard Worker if (!*swap) {
84*c9945492SAndroid Build Coastguard Worker fclose(f);
85*c9945492SAndroid Build Coastguard Worker for (i = 0; i < sizeof(req_buf)/sizeof(req_buf[0]); i++) {
86*c9945492SAndroid Build Coastguard Worker req_buf[i] = bswap_32(req_buf[i]);
87*c9945492SAndroid Build Coastguard Worker }
88*c9945492SAndroid Build Coastguard Worker *swap = 1;
89*c9945492SAndroid Build Coastguard Worker goto retry;
90*c9945492SAndroid Build Coastguard Worker } else {
91*c9945492SAndroid Build Coastguard Worker errno = EIO;
92*c9945492SAndroid Build Coastguard Worker goto error;
93*c9945492SAndroid Build Coastguard Worker }
94*c9945492SAndroid Build Coastguard Worker }
95*c9945492SAndroid Build Coastguard Worker
96*c9945492SAndroid Build Coastguard Worker if (*swap) {
97*c9945492SAndroid Build Coastguard Worker for (i = 0; i < len/sizeof(buf[0]); i++) {
98*c9945492SAndroid Build Coastguard Worker buf[i] = bswap_32(buf[i]);
99*c9945492SAndroid Build Coastguard Worker }
100*c9945492SAndroid Build Coastguard Worker }
101*c9945492SAndroid Build Coastguard Worker
102*c9945492SAndroid Build Coastguard Worker /* The first entry in every nscd response is the version number. This
103*c9945492SAndroid Build Coastguard Worker * really shouldn't happen, and is evidence of some form of malformed
104*c9945492SAndroid Build Coastguard Worker * response.
105*c9945492SAndroid Build Coastguard Worker */
106*c9945492SAndroid Build Coastguard Worker if(buf[0] != NSCDVERSION) {
107*c9945492SAndroid Build Coastguard Worker errno = EIO;
108*c9945492SAndroid Build Coastguard Worker goto error;
109*c9945492SAndroid Build Coastguard Worker }
110*c9945492SAndroid Build Coastguard Worker
111*c9945492SAndroid Build Coastguard Worker return f;
112*c9945492SAndroid Build Coastguard Worker error:
113*c9945492SAndroid Build Coastguard Worker fclose(f);
114*c9945492SAndroid Build Coastguard Worker return 0;
115*c9945492SAndroid Build Coastguard Worker }
116