xref: /aosp_15_r20/external/musl/src/passwd/nscd_query.c (revision c9945492fdd68bbe62686c5b452b4dc1be3f8453)
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