1*c9945492SAndroid Build Coastguard Worker #include <pthread.h>
2*c9945492SAndroid Build Coastguard Worker #include <byteswap.h>
3*c9945492SAndroid Build Coastguard Worker #include <string.h>
4*c9945492SAndroid Build Coastguard Worker #include <unistd.h>
5*c9945492SAndroid Build Coastguard Worker #include "pwf.h"
6*c9945492SAndroid Build Coastguard Worker #include "nscd.h"
7*c9945492SAndroid Build Coastguard Worker
itoa(char * p,uint32_t x)8*c9945492SAndroid Build Coastguard Worker static char *itoa(char *p, uint32_t x)
9*c9945492SAndroid Build Coastguard Worker {
10*c9945492SAndroid Build Coastguard Worker // number of digits in a uint32_t + NUL
11*c9945492SAndroid Build Coastguard Worker p += 11;
12*c9945492SAndroid Build Coastguard Worker *--p = 0;
13*c9945492SAndroid Build Coastguard Worker do {
14*c9945492SAndroid Build Coastguard Worker *--p = '0' + x % 10;
15*c9945492SAndroid Build Coastguard Worker x /= 10;
16*c9945492SAndroid Build Coastguard Worker } while (x);
17*c9945492SAndroid Build Coastguard Worker return p;
18*c9945492SAndroid Build Coastguard Worker }
19*c9945492SAndroid Build Coastguard Worker
__getgr_a(const char * name,gid_t gid,struct group * gr,char ** buf,size_t * size,char *** mem,size_t * nmem,struct group ** res)20*c9945492SAndroid Build Coastguard Worker int __getgr_a(const char *name, gid_t gid, struct group *gr, char **buf, size_t *size, char ***mem, size_t *nmem, struct group **res)
21*c9945492SAndroid Build Coastguard Worker {
22*c9945492SAndroid Build Coastguard Worker FILE *f;
23*c9945492SAndroid Build Coastguard Worker int rv = 0;
24*c9945492SAndroid Build Coastguard Worker int cs;
25*c9945492SAndroid Build Coastguard Worker
26*c9945492SAndroid Build Coastguard Worker *res = 0;
27*c9945492SAndroid Build Coastguard Worker
28*c9945492SAndroid Build Coastguard Worker pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
29*c9945492SAndroid Build Coastguard Worker f = fopen("/etc/group", "rbe");
30*c9945492SAndroid Build Coastguard Worker if (!f) {
31*c9945492SAndroid Build Coastguard Worker rv = errno;
32*c9945492SAndroid Build Coastguard Worker goto done;
33*c9945492SAndroid Build Coastguard Worker }
34*c9945492SAndroid Build Coastguard Worker
35*c9945492SAndroid Build Coastguard Worker while (!(rv = __getgrent_a(f, gr, buf, size, mem, nmem, res)) && *res) {
36*c9945492SAndroid Build Coastguard Worker if (name && !strcmp(name, (*res)->gr_name)
37*c9945492SAndroid Build Coastguard Worker || !name && (*res)->gr_gid == gid) {
38*c9945492SAndroid Build Coastguard Worker break;
39*c9945492SAndroid Build Coastguard Worker }
40*c9945492SAndroid Build Coastguard Worker }
41*c9945492SAndroid Build Coastguard Worker fclose(f);
42*c9945492SAndroid Build Coastguard Worker
43*c9945492SAndroid Build Coastguard Worker if (!*res && (rv == 0 || rv == ENOENT || rv == ENOTDIR)) {
44*c9945492SAndroid Build Coastguard Worker int32_t req = name ? GETGRBYNAME : GETGRBYGID;
45*c9945492SAndroid Build Coastguard Worker int32_t i;
46*c9945492SAndroid Build Coastguard Worker const char *key;
47*c9945492SAndroid Build Coastguard Worker int32_t groupbuf[GR_LEN] = {0};
48*c9945492SAndroid Build Coastguard Worker size_t len = 0;
49*c9945492SAndroid Build Coastguard Worker size_t grlist_len = 0;
50*c9945492SAndroid Build Coastguard Worker char gidbuf[11] = {0};
51*c9945492SAndroid Build Coastguard Worker int swap = 0;
52*c9945492SAndroid Build Coastguard Worker char *ptr;
53*c9945492SAndroid Build Coastguard Worker
54*c9945492SAndroid Build Coastguard Worker if (name) {
55*c9945492SAndroid Build Coastguard Worker key = name;
56*c9945492SAndroid Build Coastguard Worker } else {
57*c9945492SAndroid Build Coastguard Worker if (gid < 0 || gid > UINT32_MAX) {
58*c9945492SAndroid Build Coastguard Worker rv = 0;
59*c9945492SAndroid Build Coastguard Worker goto done;
60*c9945492SAndroid Build Coastguard Worker }
61*c9945492SAndroid Build Coastguard Worker key = itoa(gidbuf, gid);
62*c9945492SAndroid Build Coastguard Worker }
63*c9945492SAndroid Build Coastguard Worker
64*c9945492SAndroid Build Coastguard Worker f = __nscd_query(req, key, groupbuf, sizeof groupbuf, &swap);
65*c9945492SAndroid Build Coastguard Worker if (!f) { rv = errno; goto done; }
66*c9945492SAndroid Build Coastguard Worker
67*c9945492SAndroid Build Coastguard Worker if (!groupbuf[GRFOUND]) { rv = 0; goto cleanup_f; }
68*c9945492SAndroid Build Coastguard Worker
69*c9945492SAndroid Build Coastguard Worker if (!groupbuf[GRNAMELEN] || !groupbuf[GRPASSWDLEN]) {
70*c9945492SAndroid Build Coastguard Worker rv = EIO;
71*c9945492SAndroid Build Coastguard Worker goto cleanup_f;
72*c9945492SAndroid Build Coastguard Worker }
73*c9945492SAndroid Build Coastguard Worker
74*c9945492SAndroid Build Coastguard Worker if (groupbuf[GRNAMELEN] > SIZE_MAX - groupbuf[GRPASSWDLEN]) {
75*c9945492SAndroid Build Coastguard Worker rv = ENOMEM;
76*c9945492SAndroid Build Coastguard Worker goto cleanup_f;
77*c9945492SAndroid Build Coastguard Worker }
78*c9945492SAndroid Build Coastguard Worker len = groupbuf[GRNAMELEN] + groupbuf[GRPASSWDLEN];
79*c9945492SAndroid Build Coastguard Worker
80*c9945492SAndroid Build Coastguard Worker for (i = 0; i < groupbuf[GRMEMCNT]; i++) {
81*c9945492SAndroid Build Coastguard Worker uint32_t name_len;
82*c9945492SAndroid Build Coastguard Worker if (fread(&name_len, sizeof name_len, 1, f) < 1) {
83*c9945492SAndroid Build Coastguard Worker rv = ferror(f) ? errno : EIO;
84*c9945492SAndroid Build Coastguard Worker goto cleanup_f;
85*c9945492SAndroid Build Coastguard Worker }
86*c9945492SAndroid Build Coastguard Worker if (swap) {
87*c9945492SAndroid Build Coastguard Worker name_len = bswap_32(name_len);
88*c9945492SAndroid Build Coastguard Worker }
89*c9945492SAndroid Build Coastguard Worker if (name_len > SIZE_MAX - grlist_len
90*c9945492SAndroid Build Coastguard Worker || name_len > SIZE_MAX - len) {
91*c9945492SAndroid Build Coastguard Worker rv = ENOMEM;
92*c9945492SAndroid Build Coastguard Worker goto cleanup_f;
93*c9945492SAndroid Build Coastguard Worker }
94*c9945492SAndroid Build Coastguard Worker len += name_len;
95*c9945492SAndroid Build Coastguard Worker grlist_len += name_len;
96*c9945492SAndroid Build Coastguard Worker }
97*c9945492SAndroid Build Coastguard Worker
98*c9945492SAndroid Build Coastguard Worker if (len > *size || !*buf) {
99*c9945492SAndroid Build Coastguard Worker char *tmp = realloc(*buf, len);
100*c9945492SAndroid Build Coastguard Worker if (!tmp) {
101*c9945492SAndroid Build Coastguard Worker rv = errno;
102*c9945492SAndroid Build Coastguard Worker goto cleanup_f;
103*c9945492SAndroid Build Coastguard Worker }
104*c9945492SAndroid Build Coastguard Worker *buf = tmp;
105*c9945492SAndroid Build Coastguard Worker *size = len;
106*c9945492SAndroid Build Coastguard Worker }
107*c9945492SAndroid Build Coastguard Worker
108*c9945492SAndroid Build Coastguard Worker if (!fread(*buf, len, 1, f)) {
109*c9945492SAndroid Build Coastguard Worker rv = ferror(f) ? errno : EIO;
110*c9945492SAndroid Build Coastguard Worker goto cleanup_f;
111*c9945492SAndroid Build Coastguard Worker }
112*c9945492SAndroid Build Coastguard Worker
113*c9945492SAndroid Build Coastguard Worker if (groupbuf[GRMEMCNT] + 1 > *nmem) {
114*c9945492SAndroid Build Coastguard Worker if (groupbuf[GRMEMCNT] + 1 > SIZE_MAX/sizeof(char*)) {
115*c9945492SAndroid Build Coastguard Worker rv = ENOMEM;
116*c9945492SAndroid Build Coastguard Worker goto cleanup_f;
117*c9945492SAndroid Build Coastguard Worker }
118*c9945492SAndroid Build Coastguard Worker char **tmp = realloc(*mem, (groupbuf[GRMEMCNT]+1)*sizeof(char*));
119*c9945492SAndroid Build Coastguard Worker if (!tmp) {
120*c9945492SAndroid Build Coastguard Worker rv = errno;
121*c9945492SAndroid Build Coastguard Worker goto cleanup_f;
122*c9945492SAndroid Build Coastguard Worker }
123*c9945492SAndroid Build Coastguard Worker *mem = tmp;
124*c9945492SAndroid Build Coastguard Worker *nmem = groupbuf[GRMEMCNT] + 1;
125*c9945492SAndroid Build Coastguard Worker }
126*c9945492SAndroid Build Coastguard Worker
127*c9945492SAndroid Build Coastguard Worker if (groupbuf[GRMEMCNT]) {
128*c9945492SAndroid Build Coastguard Worker mem[0][0] = *buf + groupbuf[GRNAMELEN] + groupbuf[GRPASSWDLEN];
129*c9945492SAndroid Build Coastguard Worker for (ptr = mem[0][0], i = 0; ptr != mem[0][0]+grlist_len; ptr++)
130*c9945492SAndroid Build Coastguard Worker if (!*ptr) mem[0][++i] = ptr+1;
131*c9945492SAndroid Build Coastguard Worker mem[0][i] = 0;
132*c9945492SAndroid Build Coastguard Worker
133*c9945492SAndroid Build Coastguard Worker if (i != groupbuf[GRMEMCNT]) {
134*c9945492SAndroid Build Coastguard Worker rv = EIO;
135*c9945492SAndroid Build Coastguard Worker goto cleanup_f;
136*c9945492SAndroid Build Coastguard Worker }
137*c9945492SAndroid Build Coastguard Worker } else {
138*c9945492SAndroid Build Coastguard Worker mem[0][0] = 0;
139*c9945492SAndroid Build Coastguard Worker }
140*c9945492SAndroid Build Coastguard Worker
141*c9945492SAndroid Build Coastguard Worker gr->gr_name = *buf;
142*c9945492SAndroid Build Coastguard Worker gr->gr_passwd = gr->gr_name + groupbuf[GRNAMELEN];
143*c9945492SAndroid Build Coastguard Worker gr->gr_gid = groupbuf[GRGID];
144*c9945492SAndroid Build Coastguard Worker gr->gr_mem = *mem;
145*c9945492SAndroid Build Coastguard Worker
146*c9945492SAndroid Build Coastguard Worker if (gr->gr_passwd[-1]
147*c9945492SAndroid Build Coastguard Worker || gr->gr_passwd[groupbuf[GRPASSWDLEN]-1]) {
148*c9945492SAndroid Build Coastguard Worker rv = EIO;
149*c9945492SAndroid Build Coastguard Worker goto cleanup_f;
150*c9945492SAndroid Build Coastguard Worker }
151*c9945492SAndroid Build Coastguard Worker
152*c9945492SAndroid Build Coastguard Worker if (name && strcmp(name, gr->gr_name)
153*c9945492SAndroid Build Coastguard Worker || !name && gid != gr->gr_gid) {
154*c9945492SAndroid Build Coastguard Worker rv = EIO;
155*c9945492SAndroid Build Coastguard Worker goto cleanup_f;
156*c9945492SAndroid Build Coastguard Worker }
157*c9945492SAndroid Build Coastguard Worker
158*c9945492SAndroid Build Coastguard Worker *res = gr;
159*c9945492SAndroid Build Coastguard Worker
160*c9945492SAndroid Build Coastguard Worker cleanup_f:
161*c9945492SAndroid Build Coastguard Worker fclose(f);
162*c9945492SAndroid Build Coastguard Worker goto done;
163*c9945492SAndroid Build Coastguard Worker }
164*c9945492SAndroid Build Coastguard Worker
165*c9945492SAndroid Build Coastguard Worker done:
166*c9945492SAndroid Build Coastguard Worker pthread_setcancelstate(cs, 0);
167*c9945492SAndroid Build Coastguard Worker if (rv) errno = rv;
168*c9945492SAndroid Build Coastguard Worker return rv;
169*c9945492SAndroid Build Coastguard Worker }
170